2013-03-22 4 views
4
  1. Я хотел бы делать создать класс с одним родовым TKey, где TKey является одним из System.Tuple типов, которые могут быть созданы.класса сдерживания общего типа для кортежей

    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) 
    
    } 
    

Я не уверен, как это реализовать. Цель состоит в том, чтобы помешать мне реализовать класс для каждого класса кортежей.

+3

Каждый тип 'Tuple <>' имеет различное количество общих аргументов, и поэтому они являются разными типами. Вы не можете добавить ограничение для всех сразу. Есть ли причина, по которой 'TKey' * нуждается в ограничениях? – cdhowie

+0

@cdhowie Я ответил на вопрос в вашем решении, но я отправлю его здесь «есть абсолютная причина, что он должен быть одним из классов кортежей, идея состоит в том, чтобы заставить TKey действовать как ключ с n параметрами, т. Е. T1, T2, T3, ..., Tn. " –

ответ

-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

Но ... вы можете определить свой собственный базовый интерфейс, который наследуется несколькими Class1, а затем использовать этот интерфейс в качестве ограничения. Звучит неплохо, но будет работать

+1

Это не позволит 'TKey' быть любым другим типам кортежей, таким как' Tuple '. Это требуется по вопросу ОП. – cdhowie

3

Вы не можете сделать это по двум причинам.

Во-первых, вы не можете делать «или» ограничения на общие типы. Вам может потребоваться ограничение на Tuple<T1, T2>илиTuple<T1, T2, T3>. Это невозможно.

Во-вторых, вам нужно будет «пройти через» общих аргументов, например, так:

public class Class1<TKey, T1, T2> where TKey : System.Tuple<T1, T2> 

Итак, вам потребуется переменное число аргументов универсального типа для вашего класса, и это не поддерживается либо.

Если нет особых причин, почему TKeyабсолютно должен быть один из классов кортежа, оставьте его без ограничений.

+0

существует абсолютная причина того, что он должен быть одним из классов кортежей, идея состоит в том, чтобы заставить TKey действовать как ключ с n параметрами, то есть T1, T2, T3, ..., Tn. –

+0

@MaelstromYamato But * why * это должен быть один из классов кортежей? Вы собираетесь направить результат на определенный тип Tuple? Почему кто-то не может реализовать свой собственный кортежный класс, а затем использовать его? – cdhowie

+0

Чтобы уточнить: поскольку вы не можете определить, какой тип * tuple используется здесь, вы не можете передать его определенному типу 'Tuple <>', даже если бы вы (ab) использовали дженерики таким образом , – cdhowie

2

Вы не можете. Различные общие варианты Tuple не имеют разумного общего базового класса или интерфейса.

Цель общего ограничения состоит в том, чтобы сообщить компилятору, какие члены будут иметь общий тип.

13

Вы не можете, как заявили другие, но вы можете почти сделайте это.

Так все 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, и у вас может быть то, что вам нужно.

EDIT:

Некоторые основные использование:

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

Спасибо за сообщение. Я мог бы рассмотреть его для реализации. –

+0

@MaelstromYamato Удачи! Я добавил пример быстрого и грязного использования – JerKimball

+0

По моему опыту, это следующее лучшее решение сразу же, не создавая эту проблему в первую очередь. Это дает вам доступ ко всем членам тех интерфейсов, которые являются общими. – Dandy

Смежные вопросы