2011-09-21 8 views
8

与えられたobjectが指定されたTypeにキャストできるかどうかをテストします。このシナリオではC#:タイプとしての 'as'演算の実行方法

、私は、オブジェクトを持っている、と私はそれをキャストしたいタイプ表すType

public function FooBar(..., object data, Type expected) { 
    ... 
    var unboxedData = ? 
    if (unboxedData == null) { 
     .... 
    } 
    ... 
} 

私はtypeが表す型にdataをキャストするにはどうすればよいですか?

基本的に、私はこれをしたい:

var unboxedData = data as Type; 

...しかし、あなたはas文でTypeを使用することはできませんもちろん、私は何をしますか?

+4

*テスト*したい、または*キャストしたい*? – CesarGon

答えて

6

編集2:私は反射やジェネリックスなしでは不可能だと言うつもりです。リフレクションでは、コンパイル時のチェックがなく、リフレクション(またはdynamic)を使用してオブジェクトのメソッド/プロパティをさらに呼び出す必要があります。ジェネリックでは、Typeオブジェクトを単独で使用することはできません。好きなのを選びな。ジェネリックスを許可するためにあなたの呼び出しコードをリファクタリングすることは可能ですか?


許され、これはより簡単に、一般的な方法で取り扱うことができる場合は、次の

public resultType FooBar<T>(..., object data) { 
    ... 
    T unboxedData = (T)data; 
    ... 
} 

を編集:あなたがwhere T : classのジェネリック型の制約が含まれている場合も、あなたはdata as Tを使用することができます。

public something FooBar<T>(..., object data) 
    where T : class 
{ 
    ... 
    T unboxedData = data as T; 
    if (unboxedData == null) { 
     ... 
    } 
    ... 
} 
+2

IConvertibleを実装していない場合はどうなりますか? – IEHaterNumber1

+0

実際には、私は 'Convert.ChangeType'を持っていました。なぜなら、その不要な呼び出しをせずに直接キャストしようとすると、コンパイルエラーが発生したことを思い出していたからです。私はちょうどテストし、 '(T)data'はうまく働くので、それをそれに変更しました。ジェネリック型制約を 'where T:class'に含めると、' data as T'を実行することもできます。 – mellamokb

+0

これは、Type変数で始まるので、問題を解決していないようです。参照してください:http://stackoverflow.com/questions/266115/pass-an-instantiated-system-type-as-a-type-parameter-for-a-generic-classタイプのインスタンスを渡すことはできません一般的な。 – deepee1

3

...もちろん、asをasと使用することはできません言い訳、だから私は何をしますか?

重要なことに、varをこの方法で使用することはできません。だからここには何も得られない。

することはできテストそれは

if (expected.IsInstanceOfType(data)) 

と右タイプですしかし、もしあなたはまだdataにプロパティやメソッドにアクセスするための任意のまともなコードを書くことはできません。

2

C#は、実行時に指定された型が別の型と互換性があるかどうかを迅速に判断するためのasキーワードを提供します。 asキーワードを使用すると、戻り値nullをチェックして互換性を判断できます。

C#言語には、2つの項目が互換性があるかどうかを判断するためのキーワードasがあります。ただし、isキーワードとは異なり、isキーワードは、型が互換性がない場合はnull参照ではなくfalseを返します。

if (emp is SalesPerson) 
{ 
    Console.WriteLine("{0} made {1} sale(s)!", emp.Name, 
               ((SalesPerson)emp).SalesNumber); 
} 
+2

あなたは 'Type'をどこにも使用していません。タイプを明示的に定義しています。 – IEHaterNumber1

+1

あなたは 'var'を使っているので、とにかく" as "演算子を使う必要はありません。また、Aを継承するB型の変数に型aを代入したい場合は、型A =型Bを型Aとして使うことができます。 –

+2

@Pankaj私はあなたが誤解していると思います:OPは[.NET Typeクラス](http://msdn.microsoft.com/en-us/library/system.type.aspx)のインスタンスを渡しています。指定された型のメタデータ表現。 OPは、オブジェクトの型を* Typeで表される型*と比較する方法を知りました。 –

1
if (data.GetType() == t || data.GetType().IsSubclassOf(t)) 
{ 
//do your thing 
} 

それは(それにキャストすることができるので)のサブクラスで正確だかどうかを教えてください。

0

まあ、How to check if implicit or explicit cast exists?

が警戒してください...私は気にいら見つけ周り探して、私はそれを多くのテストを与えられていないが、一目で有望であると思われます。大きな負のは、それはそれを変換することができない場合に例外をスローすることです:

static bool isConvertableTo(object o, Type t) 
    { 
     try 
     { 
      var expr = Expression.Constant(o); 
      var res = Expression.Convert(expr, t); 
      return true; 
     } 
     catch { } 
     return false; 
    } 

同じアプローチを持つ別の有用なリンク:Checking if a type supports an implicit or explicit type conversion to another type with .NET

1

これはかなりトリッキーです。問題は、varが "variant"を意味するものではないということです。これは、一時的なプレースホルダのように機能し、式から型情報を推測できるようになると、C#は実際の型で埋められます。 unboxedDataは依然として強く型付けされた変数です。そのコンパイラは明示的に指定するのではなく型を理解しようとしています。コンパイル時に実行時ではなくタイピングがまだ発生していることに注意することが非常に重要です。

実行時にオブジェクトを動的にキャストする場合は、varまたはその他の具体的な型指定子を使用できません。

あなたのオプションは、2つの可能な宣言の1に制限されています:

  • オブジェクト
  • ダイナミック私はあなたが私はdynamicがある疑いがあるunboxedDataでやりたい思い何に基づいて

ターゲットの任意のメソッドを呼び出すことができるため、移動するルートはTypeです。

ここに私が思いついたのがあります。

public void FooBar(object value, Type expected) 
{ 
    dynamic unboxedData = expected.FromObject(value); 
    unboxedData.CallSomeMethodDefinedInTheTargetType(); // This will work. 
} 

これには、次の拡張方法が必要です。

public static class TypeExtension 
{ 
    public static object FromObject(this Type target, object value) 
    { 
     var convertable = value as IConvertible; 
     if (convertable != null) 
     { 
      return convertable.ToType(target, null); 
     } 
     Type type = value.GetType(); 
     if (target.IsAssignableFrom(type)) 
     { 
      return value; 
     } 
     MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); 
     foreach (MethodInfo mi in methods) 
     { 
      if (mi.ReturnType == target) 
      { 
       try 
       { 
        return mi.Invoke(null, new object[] { value }); 
       } 
       catch (TargetInvocationException caught) 
       { 
        if (caught.InnerException != null) 
        { 
         throw caught.InnerException; 
        } 
        throw; 
       } 
      } 
     } 
     throw new InvalidCastException(); 
    } 
} 

次のいずれかが該当する場合、キャストは機能します。

  • 変換する値はIConvertibleで、ターゲットタイプへの変換パスがあります。
  • 変換される値は、ターゲットタイプをサブクラス化します。
  • 変換する値は、クラス宣言でexplicit conversion operatorを定義します。
+0

私は答えを書くつもりでしたが、あなたの方がはるかに優れています。 +1 – Davy8

関連する問題