2013-03-22 6 views
13

Lassen Sie uns sagen, dass ich eine generische Klasse haben wie folgt:Wildcard Äquivalent in C# Generika

public class GeneralPropertyMap<T> 
{ 
} 

In einer anderen Klasse habe ich eine Methode, die in einer Reihe von GeneralPropertyMap<T> nimmt. In Java, um in einer Reihe zu nehmen, das jede Art von GeneralPropertyMap enthält das Verfahren würde wie folgt aussehen:

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

Wir verwenden den Platzhalter, so dass später können wir TakeGeneralPropertyMap nennen eine Reihe von GeneralPropertyMap mit jeder Art vorbei für T jeweils wie folgt aus:

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

ich versuche ohne Erfolg ein Äquivalent in C#, um herauszufinden. Irgendwelche Ideen?

+0

Haben Sie die Funktion übernehmen versucht machen 'GeneralPropertyMap [] maps' .. Ich denke, es sollte – Ankur

Antwort

3

Es gibt keine direkte Entsprechung in C#.

In C#, würde dies oft, indem Sie Ihre generische Klasse eine nicht-generische Schnittstelle oder Basisklasse implementieren erfolgen:

interface IPropertyMap 
{ 
    // Shared properties 
} 

public class GeneralPropertyMap<T> : IPropertyMap 
{ 
} 

Sie dann eine Reihe von uns passieren könnte:

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

TakePropertyMap(maps); 
+0

@EricJ wegen Kovarianzstrukturen arbeiten. Hatte das Problem falsch gelesen ... behoben –

+0

Ich verstehe die generischen Methoden, aber sie werden in diesem Fall nicht tun.Jedes Mal, wenn ich es anrufe, kann ich nur einen Typ für die GeneralPropertyMap angeben. So kann ich es nur aufrufen, indem ich entweder ein Array von GeneralPropertyMap [] oder GeneralPropertyMap und so weiter überlasse. – AxiomaticNexus

15

Generika in C# bieten stärkere Garantien als Generika in Java. Um das zu tun, was Sie in C# wollen, müssen Sie die Klasse GeneralPropertyMap<T> von einer nicht-generischen Version dieser Klasse (oder Schnittstelle) erben lassen.

public class GeneralPropertyMap<T> : GeneralPropertyMap 
{ 
} 

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

Jetzt können Sie tun:

private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps) 
{ 
} 

Und:

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

Es ist immer noch nicht gut genug, da Sie in der Schnittstelle höchstwahrscheinlich eine Methode haben möchten, die ein Platzhalterzeichen zurückgibt oder verwendet, das von der "TakeGeneralPropertyMap" -Methode nicht verwendet werden kann, weil die Schnittstelle nicht sein soll eines generischen Typs. Diese Antwort kommt jedoch zumindest nahe. Vielen Dank :-) – AxiomaticNexus

0

Machen Sie eine Schnittstelle von den Mitgliedern der GeneralPropertyMap (IGeneralPropertyMap) und dann eine IGeneralPropertyMap[] als Argument nehmen.

8

Während, wie andere bemerkt haben, es keine exakte Übereinstimmung mit Platzhaltern in C# gibt, können einige ihrer Anwendungsfälle mit covariance/contravariance abgedeckt werden.

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

Der Nachteil ist, dass Sie nicht Kovarianz mit Werttypen verwenden können, so eine neue GeneralPropertyMap<int>() zu unserer Liste hinzugefügt haben versagt bei der Kompilierung.

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

Dieser Ansatz kann bequemer sein, als eine nicht-generische Version von Klassen/Schnittstellen in Fall mit Ihnen, die Arten beschränken möchten, die GeneralPropertyMap enthalten. In diesem Fall:

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

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

können Sie haben:

var maps = new List<IGeneralPropertyMap<IMyType>> { 
    new GeneralPropertyMap<A>(), 
    new GeneralPropertyMap<B>() , 
    new GeneralPropertyMap<C>() 
}; 
TakeGeneralPropertyMap(maps);