2013-08-29 13 views
13

私はこの問題を抱えていますが、クラスからプロパティを取得するためにリフレクションを使用していますが、問題はリフレクションでオブジェクトとして返され、実際のタイプには取得できません。キャスト例外のジェネリックが無効

例えばテイク、これはクラスの場合:私はRow<object>objectから行くしようとする。しかし、それが思わ

var a = new Row<bool> 
    { 
     Name = "Foo", 
     Value = true 
    }; 

    var b = (Row<object>)a; // Works 

:1からキャスト

public class Row<T> 
{ 
    public static explicit operator Row<object>(Row<T> o) 
    { 
     return new Row<object> 
     { 
      Name = o.Name, 
      Value = o.Value 
     }; 
    } 

    public string Name { get; set; } 

    public T Value { get; set; } 
} 

Row<bool>作品Row<object>に言います私の明示的な演算子を無視し、System.InvalidCastExceptionをスロー:

var c = (object) a; // Simulate getting from reflection 

var d = (Row<object>) c; // System.InvalidCastException 

私は何が欠けていますか? dynamic代わりobject

+0

var c =(Row )a; – Ehsan

+1

あなたが期待しているものがわからない - サンプルに「明示的な演算子行(オブジェクトo)」がありません... –

+0

これは、明示的な演算子が 'Row 'を期待しているためです。 –

答えて

4

ここでの問題は、1が上に定義されていない限り、キャストは変換演算子を探していないということですキャストしようとしている値の静的型。あなたの例では、cの静的型はobjectobjectであり、変換演算子はRow<object>から派生せず、実行時例外が発生しません。

この問題は、より良いデザインで簡単に回避できるようです。

任意のタイプのRow<T>Row<object>として扱いたいと考えています。変換演算子は、これらのタイプが階層的に関連していないという事実を回避する以外には何もしません。それで、なぜそれらを関連させ、最初の問題を回避しないのですか?例えば

public abstract class Row 
{ 
    public string Name { get; set; } 

    public object Value { get; protected set; } 
} 

public class Row<T> : Row 
{ 
    public new T Value 
    { 
     get { return (T)base.Value; } 
     set { base.Value = value; } 
    } 
} 

これは、あなたがやりたいようだ:

  • あなたが今とる基底クラス(へRow<T>の任意の型にキャストすることができますので、キャストの問題が解決され、 に関係なく、NameValueに簡単にアクセスできます。
  • Row.Valueセッターが保護されているため、Row<int>をにキャストできず、Valueとなります。外からの、型の安全性を維持する。
+0

うわー、今はこのデザインをテストするだけで、本当に根本的な原因を解決するように見えます。 Jon Skeetの本を注文する必要があります... – Phil

6

使用すると、実行時の実際の型チェックを強制的に:

var c = (dynamic)a; 
var d = (Row<object>)c; // Works fine 

それはあなたのRow<T> -> Row<object>キャスト演算子を呼び出します。

+1

'明示的な演算子Row (オブジェクトo)'を宣言することはできません。 –

+0

@AdamHouldsworthそうです。 – MarcinJuraszek

+0

Visual Studioは文句を言っています。だから、私は最初にオブジェクトリフレクションの戻り値を動的にしてから自分の型にキャストする必要がありますか? – Phil

2

あなたが反射でこれを達成することができます:

public class RowHelper 
{ 
    public static Row<object> LoadRow(object o) 
    { 
     var type = o.GetType(); 
     return new Row<object> 
     { 
      Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null), 
      Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null) 
     }; 
    } 
} 

をあなたはでこれを呼び出します。

var d = RowHelper.LoadRow(c); 
関連する問題