2013-07-11 19 views
25

Lassen Sie uns sagen, dass ich eine solche Schnittstelle und konkrete Umsetzung habenSchnittstelle mit generischer Parameter vs Interface mit generischen Methoden

public interface IMyInterface<T> 
{ 
    T My(); 
} 

public class MyConcrete : IMyInterface<string> 
{ 
    public string My() 
    { 
     return string.Empty; 
    } 
} 

Also für I strings MyConcrete Implementierung schaffen, kann ich für int eine konkretere Umsetzung haben. Und das ist in Ordnung. Aber lassen Sie uns sagen, dass ich das gleiche tun wollen, aber mit generischen Methoden, so habe ich

public interface IMyInterface2 
{ 
    T My<T>(); 
} 

public class MyConcrete2 : IMyInterface2 
{ 
    public string My<string>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

So habe ich das gleiche IMyInterface2, die aber mittels T My<T>() allgemeine Verhalten definiert. In meiner konkreten Klasse möchte ich My Verhalten implementieren, aber für konkreten Datentyp - string. Aber C# erlaubt mir das nicht.

Meine Frage ist, warum ich das nicht tun kann? Mit anderen Worten, wenn ich konkrete Implementierung von MyInterface<T> als MyClass : MyInterface<string> erstellen und an diesem Punkt genericness stoppen kann, warum kann ich das mit generischer Methode nicht tun - ?

+1

Sie können * Fähigkeiten nicht reduzieren, wenn Sie Typen erben, Sie können nur zu ihnen hinzufügen. –

Antwort

29

Ihre generische Methode Implementierung hat auch generisch sein, so muss es sein:

public class MyConcrete2 : IMyInterface2 
{ 
    public T My<T>() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Warum können Sie My<string>() hier nicht? Weil der Interface-Vertrag eine Methode benötigt, die mit jedem Typparameter T aufgerufen werden kann und Sie diesen Vertrag erfüllen müssen.

Warum können Sie nicht stoppen genericness in diesem Punkt? Da wäre es Situationen verursachen wie folgt vor:

Klasse Erklärungen:

public interface IMyInterface2 
{ 
    T My<T>(t value); 
} 

public class MyClass21 : IMyInterface2 
{ 
    public string My<string>(string value) { return value; } 
} 

public class MyClass22 : IMyInterface2 
{ 
    public int My<int>(int value) { return value; } 
} 

Verbrauch:

var item1 = new MyClass21(); 
var item2 = new MyClass22(); 

// they both implement IMyInterface2, so we can put them into list 
var list = new List<IMyInterface2>(); 
list.Add(item1); 
list.Add(item2); 

// iterate the list and call My method 
foreach(IMyInterface2 item in list) 
{ 
    // item is IMyInterface2, so we have My<T>() method. Choose T to be int and call with value 2: 
    item.My<int>(2); 

    // how would it work with item1, which has My<string> implemented? 
} 
+1

Es braucht Öffentlichkeit 'T My () sein' –

+0

wenn ich konkrete Umsetzung MyInterface als MyClass erstellen: MyInterface und stoppe genericness in diesem Punkt, warum kann ich nicht mit generischer Methode tun - T My () –

+1

@JevgenijNekrasov Überprüfen Sie mein Update. Ich habe eine Situation gezeigt, in der Ihre 'My ' Implementierung fehlschlagen würde. – MarcinJuraszek

0

Weil Ihre Schnittstelle deklariert eine generische Methode T My<T>(), aber Sie Implementierung nicht implementieren Sie eine Funktion mit dieser spezifischen Signatur. in Ihrem ersten Beispiel

Um das zu erreichen, was Sie wollen, müssen Sie den T allgemeine Parameter für die Schnittstelle zur Verfügung zu stellen stattdessen: die Definition ist der Platzhalter für die Aufbewahrung

public interface IMyInterface2<T> 
{ 
     T My(); 
} 

public class MyConcrete2 : IMyInterface2<string> 
{ 
    public string My() 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

Ich weiß, wie ich erreichen kann, was ich will, ich möchte wissen, warum ich Generika nicht stoppen kann, wie ich mit den Schnittstellen –

2

, wenn Sie die generische Methode schreiben. Der tatsächliche Typ wird beim Aufruf der Methode angezeigt. also sollten Sie stattdessen schreiben

public T My<T>() 
{ 
    throw new NotImplementedException(); 
} 

und wenn Sie die Methode aufrufen, können Sie die Zeichenfolge dort verwenden.

+0

kann Ich möchte Generizität zu stoppen, wie ich mit generischen Schnittstelle, z. MyClass: MyInterface

0

Ihre Lösung funktioniert aus zwei Gründen nicht.

Erstens ist eine Schnittstelle ein Vertrag. Wenn Sie IMyInterface2 implementieren, garantieren Sie, dass Sie eine Funktion namens My implementieren, die einen generischen Typparameter verwendet und diesen Typ zurückgibt. MyConcrete2 tut dies nicht.

Zweitens erlauben C# Generika keine Art von Typ-Parameter-Spezialisierung. (Ich wünschte, dass C# dies unterstützt.) Dies ist eine häufige Sache in C++ - Vorlagen, in denen Ihr Beispiel kompiliert würde, aber alle Verwendungen von MyConcrete2 könnten nicht kompiliert werden, wenn sie My nicht mit einer string aufrufen.

Verwandte Themen