2015-09-22 33 views
2

我從方法中取回對象。該對象是對象類型的,並且由於向後兼容性,我無法更改此對象。如果它屬於某種類型(Response<T>波紋管),那麼我需要訪問類型爲T的屬性Payload,以便我可以將其作爲另一個對象的一部分序列化併發送出去。問題是因爲我不知道T的類型,所以即使我不關心它的類型,我也不能將對象轉換成Response<T>來訪問PayloadCast通用參數

這是我與通用類型的對象:

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

UPDATE:

我需要能夠序列化和反序列化這個對象。原本Response有類型的屬性Payload。當Response<T>被反序列化時,這導致序列化問題,因爲Payload屬性的類型爲Newtonsoft.Json.Linq.JObject,無法將其轉換爲T。這裏有一個例子:https://dotnetfiddle.net/uc15HD

的問題是,我是走錯了方向和反序列化工作,如果我投Tobject,而不是試圖投objectT。當我將該值存儲爲其特定類型T時,序列化程序知道要將字符串反序列化到什麼位置。 下面是使用下面的喬恩的回答一個例子:https://dotnetfiddle.net/KwudAx

下面是一個使用類似的例子使用的協方差的馬蒂亞斯的解決方案:https://dotnetfiddle.net/kCjZr4

+0

這真的不清楚你想要做什麼......是'data'意味着是一個'Type',而不是類型的實例?這就是你所調用的內容的樣子,但是你試圖將它轉換爲「響應'...... –

+0

並且你可以根據需要更改」響應「嗎?有一個非通用的抽象基類型? –

+0

對不起。數據是一種類型的實例。它有時會是類型響應。我無法真正改變它是「有時」的。但是我需要特別處理它。 – bygrace

回答

5

若要編譯時的屬性的名稱的檢查,你可以保持動態類型,但得到運行的「迷你編譯」做艱苦的工作:

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

謝謝!我的序列化問題是我走錯了方向。我將有效載荷保存在對象類型Response的屬性中,並從響應中引用它,而不是將有效內容保存在類型爲T的屬性中,並具有將其轉換爲對象的屬性。我將在我的問題中添加代碼示例的鏈接來說明這一點。 – bygrace

+0

我只是不得不使用這個解決方案,因爲枚舉不像其他解決方案所要求的那樣支持協方差。 – bygrace

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 
+0

謝謝!我希望我能把你的和喬恩的答案都標記爲答案。我將使用您的解決方案添加示例。 – bygrace

+0

@bygrace沒問題。這裏的答案是提供更多方法來解決相同的問題。這對未來的訪問者很有用(甚至你!) –

+0

優雅的解決方案! –