2013-03-22 5 views
13

Скажем, у меня есть общий класс следующим образом:Wildcard эквивалент в C# дженериков

public class GeneralPropertyMap<T> 
{ 
} 

В какой-то другой класс у меня есть метод, который принимает в массиве GeneralPropertyMap<T>. В Java, для того, чтобы взять в массив, который содержит любой тип GeneralPropertyMap метод будет выглядеть следующим образом:

private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps) 
{ 
} 

Мы используем подстановочные так, что позже мы можем назвать TakeGeneralPropertyMap проходя кучу GeneralPropertyMap с любым типом для T каждый, как это:

GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3]; 
maps[0] = new GeneralPropertyMap<String>(); 
maps[1] = new GeneralPropertyMap<Integer>(); 
maps[2] = new GeneralPropertyMap<Double>(); 
//And finally pass the array in. 
TakeGeneralPropertyMap(maps); 

Я пытаюсь выяснить эквивалент в C# без успеха. Есть идеи?

+0

Вы пробовали сделать функцию принять 'GeneralPropertyMap [] maps' .. Я думаю, он должен работать из-за Ковариационный – Ankur

ответ

3

В C# нет прямого эквивалента этому.

В C#, то это часто может быть сделано путем иметь ваш общий класс реализации необщего интерфейса или базового класса:

interface IPropertyMap 
{ 
    // Shared properties 
} 

public class GeneralPropertyMap<T> : IPropertyMap 
{ 
} 

Затем можно передать массив из них:

IPropertyMap[] maps = new IPropertyMap[3]; 
// ... 

TakePropertyMap(maps); 
+0

@EricJ. Изменил проблему ... исправлено –

+0

Я понимаю общие методы, но в этом случае они не будут работать.Каждый раз, когда я его вызываю, я могу указать только один тип для GeneralPropertyMap. Поэтому я могу назвать это передачей либо массива GeneralPropertyMap [], либо GeneralPropertyMap и так далее. – AxiomaticNexus

15

Дженерики в C# обеспечивают более надежные гарантии, чем generics в Java. Поэтому, чтобы делать то, что вы хотите в C#, вы должны позволить классу GeneralPropertyMap<T> наследовать от не-универсальной версии этого класса (или интерфейса).

public class GeneralPropertyMap<T> : GeneralPropertyMap 
{ 
} 

public class GeneralPropertyMap 
{ 
    // Only you can implement it: 
    internal GeneralPropertyMap() { } 
} 

Теперь вы можете сделать:

private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps) 
{ 
} 

И:

GeneralPropertyMap[] maps = new GeneralPropertyMap[3]; 
maps[0] = new GeneralPropertyMap<String>(); 
maps[1] = new GeneralPropertyMap<Integer>(); 
maps[2] = new GeneralPropertyMap<Double>(); 
TakeGeneralPropertyMap(maps); 
+1

Это все еще не достаточно хорошо, так как в интерфейсе вы, скорее всего, захотите иметь метод, который возвращает или принимает шаблон для использования из метода TakeGeneralPropertyMap, который вы не можете сделать, потому что мы не хотим, чтобы интерфейс был общего типа. Однако этот ответ по крайней мере приближается. Благодаря :-) – AxiomaticNexus

0

сделать интерфейс из членов GeneralPropertyMap (IGeneralPropertyMap), а затем взять IGeneralPropertyMap[] в качестве аргумента.

8

Хотя, как отмечали другие, нет точного соответствия подстановочным символам в C#, некоторые из их вариантов использования могут быть покрыты covariance/contravariance.

public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so 
             // we need to introduce an interface... 

public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class 
                  // inherit from it 

//now our method becomes something like 
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){} 

// and you can do 
    var maps = new List<IGeneralPropertyMap<Object>> { 
     new GeneralPropertyMap<String>(), 
     new GeneralPropertyMap<Regex>() 
    }; 
    //And finally pass the array in. 
    TakeGeneralPropertyMap<Object>(maps); 

Проблема заключается в том, что вы не можете использовать ковариации с типами значений, так что добавление нового GeneralPropertyMap<int>() в нашем списке терпит неудачу во время компиляции.

cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>' 

Этот подход может быть более удобным, чем с не-дженерик ваших классов/интерфейсов в случае, если вы хотите, чтобы ограничить типы, которые могут содержать GeneralPropertyMap. В этом случае:

public interface IMyType {} 
public class A : IMyType {} 
public class B : IMyType {} 
public class C : IMyType {} 

public interface IGeneralPropertyMap<out T> where T : IMyType {} 

позволяет иметь:

var maps = new List<IGeneralPropertyMap<IMyType>> { 
    new GeneralPropertyMap<A>(), 
    new GeneralPropertyMap<B>() , 
    new GeneralPropertyMap<C>() 
}; 
TakeGeneralPropertyMap(maps); 
Смежные вопросы