强制转换泛型参数
本文关键字:参数 泛型 转换 | 更新日期: 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