2017-11-22 6 views
0

私のC#アプリケーションでは、ユーザーにタプルを表示する必要があります。問題は、タプルはどのような形式でもかまいません。コンパイル時にタプルがどのように見えるかわからないので、実行時にそれを表示するためにイントロスペクトする必要があります。第1の問題は、タプル内の各コンポーネントのタイプを識別することであり、第2の問題は各コンポーネントの値を取得することです。タプルのC#ランタイムイントロスペクション

各コンポーネントの値を取得するには、Item1、Item2などが含まれているようですが、インデックスでアイテムを取得する方法はありますか?現在、私のコードは、コンポーネントがどのように反復処理されるかを決定するためにコンポーネントの数を使用する必要があるため、本当に厄介です(下記参照)。しかし、もっと大きな問題は、Tupleオブジェクトを取得する方法がわからないために要素を取得する方法です。次のコードがコンパイルされますが、実行時にオブジェクトのTupleへのキャストによってこの形式のエラーがスローされます。

[System.Tuple 2[System.String,System.Byte[]]' to type 'System.Tuple 2 [System.Object、System.Object]]のオブジェクトをキャストすることができません。

キャストに失敗したように見えますが(なぜならわかると思いますが)、キャストを書き直す方法はわかりません。私は次のようなものを試しました:

object rowObject = ((Tuple<tupleTypeArray[0], tupleTypeArray[1]>)tupleObject).Item1; 

これはコンパイルされません。助けていただければ幸いです!

tupleObject = SomeTupleGotFromMethodCall(); 
Type tupleType = tupleObject.GetType(); 
Type[] tupleTypeArray = tupleType.GenericTypeArguments; 
int tupleLength = tupleType.GenericTypeArguments.Count<Type>(); 
for (int i = 0; i < tupleLength; i++) 
{ 
    if (tupleLength == 1) 
    { 
     if (i == 0) 
     { 
      Type firstType = tupleTypeArray[0]; 
      object rowObject = ((Tuple<object>)tupleObject).Item1; 
      if (rowObject != null) 
      { 
       display(rowObject); 
      } 
     } 
    } 

    if (tupleLength == 2) 
    { 
     if (i == 0) 
     { 
      object rowObject = ((Tuple<object, object>)tupleObject).Item1; 
      if (rowObject != null) 
      { 
       display(rowObject); 
      } 
     } 

     if (i == 1) 
     { 
      object rowObject = ((Tuple<object, object>)tupleObject).Item2; 
      display(rowObject); 
     } 
    } 

    ... 
} 
+1

リストとしてタプルを使用しては決して良いアイデアのようなものです、あなたはタプルを返す、あなたのメソッドの実装を持っているのですか? – Boo

+0

いいえ - 私は戻ってくるものを支配しません。これは別のライブラリです。上記のコードに達する前に、タプルだけが戻って来る(そして私はこれらの他の型を扱う)唯一のオブジェクトではありません。 – user304582

+0

最初の2つの行が意味をなさないので、最初のすべての 'オブジェクト'は型です。 – Boo

答えて

1

これは動作しないことができます。

object rowObject = ((Tuple<object>)tupleObject).Item1; 

Tuple<int>Tuple<object>ではありませんので。 intobjectから継承しているからといって、Tuple<int>Tuple<object>を継承しているわけではありません。

あなたが本当にやりたいことは、不明な種類のオブジェクトのすべてのプロパティを取得して表示することです。特にこれはタプルの問題ではありません。他のオブジェクトと違うタプルでこれを行うことについては何もありません。プロパティはプロパティです。彼らが野原でない限り。それらは全く特性ではありません。しかし、タプルでは、​​それらはプロパティです。

したがって、任意のオブジェクトのパブリックプロパティの名前と値をすべて返す簡単な拡張メソッドを記述するだけで、プロパティの型もスローされます。コンプリート。

プロパティの名前と値を取得したら、任意の方法で表示するコードを記述できます。

public static class Extensions 
{ 
    // nuget Install-Package "System.ValueTuple" if the compiler gives you any backtalk 
    public static List<(String Name, Type Type, Object Value)> 
     GetPublicPropertiesWithValues(this object obj) 
    { 
     return 
      obj.GetType() 
      .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      .Select(p => (
       Name: p.Name, 
       Type: p.PropertyType, 
       Value: p.GetValue(obj) 
      )) 
      .ToList(); 
    } 
} 

デモ:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var tuple = new Tuple<String, Object, double, float, Tuple<String, String>>(
      "foo", "bar", 34.56, 5.43f, new Tuple<string, string>("Fred", "Barney")); 

     tuple.GetPublicPropertiesWithValues().ForEach(p => Console.WriteLine(p)); 

     Console.ReadKey(); 
    } 
} 

出力:

(Item1, System.String, foo) 
(Item2, System.Object, bar) 
(Item3, System.Double, 34.56) 
(Item4, System.Single, 5.43) 
(Item5, System.Tuple`2[System.String,System.String], (Fred, Barney)) 
関連する問題