我从一个方法中得到一个对象.该对象属于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; }
}
Run Code Online (Sandbox Code Playgroud)
这是我想做的事情:
// 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...
}
Run Code Online (Sandbox Code Playgroud)
但我能找到的唯一方法是使用动力学.
// Will sometimes be of type Response<T>
object data = LegacyCode();
if (data.GetType().IsGenericType && data.GetType().GetGenericTypeDefinition() == typeof(Response<>)) {
var payload = ((dynamice)data).Payload;
}
Run Code Online (Sandbox Code Playgroud)
不要问为什么事情就像他们一样(我想知道自己).我必须做代码体操以保持在这个系统中的向后兼容性.我只想要编译时检查属性的名称.
这是一个小提琴: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使用协方差的解决方案的类似示例: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>...
}
Run Code Online (Sandbox Code Playgroud)
更好的解决方案是添加非泛型接口或额外的基类.例如:
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; } }
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用:
var payloadHolder = data as IPayloadHolder;
if (payloadHolder != null)
{
var payload = payloadHolder.Payload;
}
Run Code Online (Sandbox Code Playgroud)
我相信你需要使用协方差.
设计界面IResponse<out T>:
public interface IResponse<out T>
{
public T Payload { get; }
}
Run Code Online (Sandbox Code Playgroud)
并实施它Response<T>.现在你可以把它投射到IResponse<object>:
Response<string> x = new Response<string>();
IResponse<object> y = x; // implicit cast
Run Code Online (Sandbox Code Playgroud)