转换泛型参数

时间:2015-09-22 21:21:01

标签: c# generics

我从方法中获取了一个对象。该对象属于object类型,由于向后兼容性,我无法对其进行更改。如果它是某种类型(Response<T>下方),那么我需要访问类型为Payload的属性T,以便我可以将其序列化为另一个对象的一部分并发送它关了。问题在于,由于我不知道T的类型,因此即使我不知道,我也无法将对象投放到Response<T>以访问Payload关心它的类型。

这是我的通用类型的对象:

public class Response
{
   public int Status { get; set; }
   public string Message { get; set; }
}

public class Response<T> : Response
{
   public T Payload { get; set; }
}

以下是我想做的事情:

// Will sometimes be of type Response<T>
object data = LegacyCode();
if (data.GetType().IsGenericType && data.GetType().GetGenericTypeDefinition() == typeof(Response<>)) {
   var payload = ((Response<object>)data).Payload; // Unable to cast object of type...
}

但我能找到的唯一方法是使用动力学。

// Will sometimes be of type Response<T>
object data = LegacyCode();
if (data.GetType().IsGenericType && data.GetType().GetGenericTypeDefinition() == typeof(Response<>)) {
   var payload = ((dynamice)data).Payload;     
}

不要问为什么事情就像他们一样(我自己也在想)。我必须做代码体操以保持在这个系统中的向后兼容性。 我只想要编译时检查属性的名称。

这是一个小提琴:https://dotnetfiddle.net/dXxHbD

更新

我需要能够序列化和反序列化这个对象。最初Response的属性Payload类型为object。这导致序列化问题在Response<T>被反序列化时,因为Payload属性类型为Newtonsoft.Json.Linq.JObject,无法转换为T。以下是一个示例:https://dotnetfiddle.net/uc15HD

问题在于,如果我将T转换为object而不是尝试将object转换为T,我的方向错误并且反序列化有效。当我将值存储为其特定类型T时,序列化程序知道要将字符串反序列化的内容。 以下是Jon的回答:https://dotnetfiddle.net/KwudAx

以下是使用Matias&#39;的类似示例。使用协方差的解决方案:https://dotnetfiddle.net/kCjZr4

2 个答案:

答案 0 :(得分:5)

要获得属性名称的编译时检查,您可以保持动态类型,但获取运行时&#34;迷你编译器&#34;努力工作:

object data = LegacyCode();
object payload = GetPayload(data);
// Use payload

...

private static object GetPayload<T>(Response<T> response)
{
    return response.Payload;
}

public static object GetPayload(object data)
{
    // Fallback method. You could return null here and use
    // that to indicate in the calling code that it wasn't a
    // Response<T>...
}

更好的解决方案是添加非泛型接口或额外的基类。例如:

public class Response
{
   public int Status { get; set; }
   public string Message { get; set; }
}

public interface IPayloadHolder
{
    public object Payload { get; }
}

public class Response<T> : Response, IPayloadHolder
{
   public T Payload { get; set; }

   // By using explicit interface implementation, this
   // doesn't get in the way for normal usage.
   IPayloadHolder.Payload { get { return Payload; } }
}

然后你可以使用:

var payloadHolder = data as IPayloadHolder;
if (payloadHolder != null)
{
    var payload = payloadHolder.Payload;
}

答案 1 :(得分:5)

我相信您需要使用covariance

设计界面IResponse<out T>

public interface IResponse<out T>
{
   public T Payload { get; }
}

并在Response<T>上实施。现在您可以将其投射到IResponse<object>

Response<string> x = new Response<string>();
IResponse<object> y = x; // implicit cast