7
  1. TKey は、作成可能なSystem.Tupleタイプの 1 つです。

    public class Class1<TKey> where TKey : System.Tuple
    { 
           /// Class Stuff Goes Here where TKey is one of the 8 tuple 
               types found in the link in (1)
    
    }
    

これを実装する方法がよくわかりません。目標は、タプル クラスごとにクラスを実装しないようにすることです。

4

5 に答える 5

21

他の方がおっしゃる通りできませんが、ほぼできます。

したがって、すべてのTuple<...>クラスには次のような署名があります。

public class Tuple<T1, ...> : 
    IStructuralEquatable, 
    IStructuralComparable, 
    IComparable, 
    ITuple

保存されているこれらのインターフェイスはすべてITuple公開されているため (ITupleは内部インターフェイスです)、次のようなものを作成してみることができます。

public interface ITupleKey<TKey>
    where TKey : IStructuralEquatable, IStructuralComparable, IComparable
{
}

「でも待ってください!」とあなたは言います。

まあ、あなたはできません。しかし、私が言ったように、これはほとんどの方法です-幸いなことに、IStructuralEquatable(IStructuralComparableフレームワークレベルでは、当然のことながら) 次の型でのみ使用されます:

System.Array
System.Tuple<T1>
System.Tuple<T1,T2>
System.Tuple<T1,T2,T3>
System.Tuple<T1,T2,T3,T4>
System.Tuple<T1,T2,T3,T4,T5>
System.Tuple<T1,T2,T3,T4,T5,T6>
System.Tuple<T1,T2,T3,T4,T5,T6,T7>
System.Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>

だからかなり近いです。TKeyこれを、実際には の変形である実行時チェックと組み合わせると、Tuple必要なものが得られる可能性があります。

編集:

基本的な使い方:

public class Class1<TKey> 
    where TKey : IStructuralEquatable, IStructuralComparable, IComparable
{ 
}

// will compile
var classTup1 = new Class1<Tuple<int>>();
var classTup2 = new Class1<Tuple<int,int>>();
var classTup3 = new Class1<Tuple<int,int,int>>();
var classTup4 = new Class1<Tuple<int,int,int,int>>();
var classTup5 = new Class1<Tuple<int,int,int,int,int>>();

// won't compile
var badclassTup1 = new Class1<int>();
var badclassTup2 = new Class1<string>();
var badclassTup3 = new Class1<object>();

そして、私は明らかに気が狂ってしまったので、ここで何ができるか見てみましょう。

public class Class1<TKey> 
    where TKey : IStructuralEquatable, IStructuralComparable, IComparable
{ 
    public Class1(TKey key)
    {
        Key = key;
        TupleRank = typeof(TKey).GetGenericArguments().Count();
        TupleSubtypes = typeof(TKey).GetGenericArguments();
        Console.WriteLine("Key type is a Tuple (I think) with {0} elements", TupleRank);
        TupleGetters = 
            Enumerable.Range(1, TupleRank)
                .Select(i => typeof(TKey).GetProperty(string.Concat("Item",i.ToString())))
                .Select(pi => pi.GetGetMethod())
                .Select(getter => Delegate.CreateDelegate(
                            typeof(Func<>).MakeGenericType(getter.ReturnType), 
                            this.Key, 
                            getter))
                .ToList();
    }

    public int TupleRank {get; private set;}
    public IEnumerable<Type> TupleSubtypes {get; private set;}
    public IList<Delegate> TupleGetters {get; private set;}
    public TKey Key {get; private set;}

    public object this[int rank]
    {
        get { return TupleGetters[rank].DynamicInvoke(null);}
    }
    public void DoSomethingUseful()
    {
        for(int i=0; i<TupleRank; i++)
        {
            Console.WriteLine("Key value for {0}:{1}", string.Concat("Item", i+1), this[i]);
        }
    }
}

テスト装置:

var classTup1 = new Class1<Tuple<int>>(Tuple.Create(1));
var classTup2 = new Class1<Tuple<int,int>>(Tuple.Create(1,2));
var classTup3 = new Class1<Tuple<int,int,int>>(Tuple.Create(1,2,3));
var classTup4 = new Class1<Tuple<int,int,int,int>>(Tuple.Create(1,2,3,4));
var classTup5 = new Class1<Tuple<int,int,int,int,int>>(Tuple.Create(1,2,3,4,5));

classTup1.DoSomethingUseful();
classTup2.DoSomethingUseful();
classTup3.DoSomethingUseful();
classTup4.DoSomethingUseful();
classTup5.DoSomethingUseful();

出力:

Key type is a Tuple (I think) with 1 elements
Key type is a Tuple (I think) with 2 elements
Key type is a Tuple (I think) with 3 elements
Key type is a Tuple (I think) with 4 elements
Key type is a Tuple (I think) with 5 elements
Key value for Item1:1
Key value for Item1:1
Key value for Item2:2
Key value for Item1:1
Key value for Item2:2
Key value for Item3:3
Key value for Item1:1
Key value for Item2:2
Key value for Item3:3
Key value for Item4:4
Key value for Item1:1
Key value for Item2:2
Key value for Item3:3
Key value for Item4:4
Key value for Item5:5
于 2013-03-22T20:00:34.987 に答える
7

インターフェイスに基づいてクラス (または私の場合はメソッド) を制約することを誰も提案していないことに驚いていITupleます。あなたの例を説明するには:

public class Class1<T> where T : ITuple

System.Runtime.CompilerServicesアセンブリを参照する必要があります。

私の特定の使用例は、未知の形状のタプルのコレクションを反復処理したい場合です。私の解決策は次のようなものでした:

public static void ProcessTupleCollection<T>(this IEnumerable<T> collection) where T: ITuple
{
    var type = typeof(T);
    var fields = type.GetFields();
    foreach (var item in collection)
    {
        foreach (var field in fields)
        {
            field.GetValue(item);
        }
    }
}

私はこれが古いものであることを知っていますが、これがそれに出くわす可能性のある人々の助けになることを願っています:)

于 2019-09-17T16:32:51.610 に答える
-1

そのようです:

public class Class1<TKey,P,Q> where TKey : System.Tuple<P,Q>
{ 
       /// Class Stuff Goes Here where TKey is one of the 8 tuple 
           types found in the link in (1)

}

Tuple のジェネリック パラメータをクラスに追加します。

以下のコメントによると、これをインターフェイスやリフレクションなしで 1 つのクラスに結合する方法はありません。もしあれば、複数の Tuple クラスはありませんでした

しかし... 複数の Class1 によって継承される独自の基本インターフェイスを定義し、そのインターフェイスを制約として使用できます。きれいに聞こえませんが、うまくいきます

于 2013-03-22T19:49:24.057 に答える