强制转换泛型参数

本文关键字:参数 泛型 转换 | 更新日期: 2023-09-27 18:14:06

我从一个方法中得到一个对象。对象的类型是object,由于向后兼容性,我不能更改它。如果它是特定类型的(下面的Response<T>),那么我需要访问类型为T的属性Payload,这样我就可以将它序列化为另一个对象的一部分并发送它。问题是,因为我不知道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有一个类型为object的属性Payload。这在反序列化Response<T>时导致了序列化问题,因为Payload属性的类型是Newtonsoft.Json.Linq.JObject,不能强制转换为T。下面是一个例子:https://dotnetfiddle.net/uc15HD

问题是我走错了方向,如果我将T转换为object,而不是尝试将object转换为T,反序列化工作。当我将值存储为其特定类型T时,序列化程序知道将字符串反序列化为什么。下面是Jon回答的一个例子:https://dotnetfiddle.net/KwudAx

下面是一个类似的例子,使用Matias的协方差解决方案:https://dotnetfiddle.net/kCjZr4

强制转换泛型参数

要获得属性名称的编译时检查,您可以保留动态类型,但让运行时的"迷你编译器"来完成艰苦的工作:

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;
}

我认为您需要使用协方差

设计一个接口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