2012-04-09 3 views
6

Ich habe eine Schnittstelle wie folgt aus:Wie Typ T in Schnittstelle in C# zurückgegeben?

public interface IUser{ 
    //some properties here 

    T ToDerived(User u); 
} 

Ich bin Neuentwicklung Schnittstelle, so ist hier, was ich zu erreichen bin versucht. Ich werde eine Basisklasse haben

public class User 

, die nicht die obige Schnittstelle implementiert. Dann habe ich eine abgeleitete Klasse

SalesUser : User, IUser 
{ 
    //no properties needed because they exist in the User class 

    SalesUser ToDerived(User u) 
    { 
     //code for converting a base User to a derived SalesUser 
    } 
} 

Ich mag würde die Funktion für ToDerived (User u) in der SalesUser Klasse schreiben, aber in der Schnittstelle, weiß ich nicht, wie das als Erklärung ToDerived Methode definieren das habe ich jetzt in der schnittstelle nicht kompiliert.

Ich hoffe, das macht Sinn.

+1

(http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) ist ein Link zu einem Blog von Eric, der für diese Frage relevant ist. Es enthält sowohl ein Beispiel, das der untenstehenden Antwort sehr ähnlich sieht, als auch Fehler bei der Verwendung dieses Entwurfsmechanismus. – Servy

Antwort

14
public interface IUser<T> where T : User 
{ 
    //some properties here 

    T ToDerived(User u); 
} 

SalesUser : User, IUser<SalesUser> 
{ 
    //no properties needed because they exist in the User class 

    SalesUser ToDerived(User u) 
    { 
     //code for converting a base User to a derived SalesUser 
    } 
} 

nicht sicher, das ist, was Sie wollen, aber ich hinzugefügt, um eine generische Typ Einschränkung für die Schnittstelle, um sicherzustellen, dass der generische Typ User oder erbt von ihm.

+0

Beat mich dazu, aber ich würde 'where T: User' hinzufügen. –

+0

@JimSchubert - Ich dachte es und fügte hinzu, während Sie kommentieren;) – Oded

+0

Sie schlugen mich dazu zweimal :( –

0

eine Schnittstelle Denken Sie daran, definiert eine Klasse und ihre Mitglieder ohne jede Implementierung bereitstellt, kann yo eine Schnittstelle schaffen, sondern die Schnittstelle muss die implementierende Klasse haben.

+0

Wie beantwortet das die Frage? – Oded

+0

Ich möchte die Funktion für ToDerived (Benutzer u) in der SalesUser-Klasse schreiben, aber in der Schnittstelle, weiß ich nicht, wie dies als ToDerived-Methode-Deklaration zu definieren, ich weiß nicht, ob ich falsch liege. –

3

Die Antwort von Oded löst das Problem Kompilierung, so dass Sie die ToDerived Methode definieren, die die Schnittstelle erfüllt. Wie ich im Kommentar gesagt habe, bin ich mir nicht sicher, ob dies die beste Implementierung ist.

Das Hauptproblem habe ich mit ihm ist, dass wie diese Umwandlungsverfahren normalerweise in einem statischen Kontext benötigt werden. Sie haben keine Instanz von SalesUser; Sie wollen einen Benutzer und haben einen Benutzer, also rufen Sie die Methode im statischen Kontext auf (SalesUser.ToDerived(myUser)) und Sie erhalten einen SalesUser (die Methode würde geeigneterweise FromUser() oder ähnlich genannt werden). Die Methode, die Sie in der Schnittstelle angeben, erfordert, dass Sie bereits einen SalesUser haben, um einen Benutzer in einen SalesUser zu konvertieren. Die einzige Situation, die ich mir vorstellen kann, in der Sie wirklich einen bestehenden SalesUser benötigen, ist ein "partieller Klon"; Sie erstellen eine neue SalesUser-Instanz mit Informationen aus dem übergebenen Benutzer und aus dem SalesUser, auf dem Sie die Methode aufrufen. In allen anderen Fällen benötigen Sie entweder keinen SalesUser (Konvertierungen, die wie erwähnt statisch sein sollten), oder Sie benötigen keinen Benutzer (eine "Klon" - oder "Deep Copy" -Methode, die eine neue Instanz mit dem erzeugt gleiche Daten wie die Instanz, auf der Sie die Methode aufgerufen haben).

Auch die Verbraucher der Klasse müssen wissen, dass sie ToDerived() aufrufen, um muss die Konvertierung von einem Benutzer zu einem SalesUser auszuführen. Normalerweise würde ein C# -Programmierer eine explizite oder implizite erwartet Umwandlung zur Verfügung steht:

public class SalesUser 
{ 

    public static explicit operator (User user) 
    { 
     //perform conversion of User to SalesUser 
    } 

} 

//the above operator permits the following: 
mySalesUser = (SalesUser)myUser; 

... OR, einen Umwandlungsoperator andernfalls würde man eine SalesUser mit einem Benutzer erwarten zu können, konstruieren:

public class SalesUser:IUser 
{ 
    public SalesUser(User user) 
    { 
     //initialize this instance using the User object 
    } 
} 

//the above allows you to do this: 
mySalesUser = new SalesUser(myUser); 

//and it also allows the definition of a method like this, 
//which requires the generic to be an IUser and also requires a constructor with a User 
public void DoSomethingWithIUser<T>(User myUser) where T:IUser, new(User) 
{ 
    //...which would allow you to perform the "conversion" by creating a T: 
    var myT = new T(myUser); 
} 

nun statische Mitglieder nicht erfüllen Schnittstellendefinitionen und Schnittstellen statische Elemente oder Konstruktor Signaturen nicht definieren können. Dies sagt mir, dass die IUser-Schnittstelle nicht versuchen sollte, die Konvertierungsmethode zu definieren; stattdessen können Methoden, die einen IUser irgendeiner Art benötigen, dies einfach angeben, und der Benutzer kann eine Implementierung bereitstellen, wenn dies erforderlich ist, ohne dass die Implementierung wissen muss, dass sie in sich selbst konvertieren kann. [Hier]

+0

Sie haben Recht, Oded hat das Problem gelöst und meine Frage genau so beantwortet, wie ich gesucht habe. Allerdings mag ich Ihre Erklärung dazu und warum ich dieses Designmuster nicht verwenden sollte, da diese spezielle Methode typischerweise eine statische Methode wäre (der ich zustimme). Wenn ich versuche, Ihr Beispiel zu erstellen, beachten Sie jedoch, dass ich die SalesUser-Klasse benötigen, um die Basisbenutzerklasse zu erben. Öffentliche Klasse SalesUser: Benutzer, IUser Also, wenn ich dies versuche, funktioniert Ihre explizite Methode nicht. "benutzerdefinierte Konvertierungen zu oder von einer Basisklasse sind nicht erlaubt." – jaressloo

+0

Die Konstruktor-basierte "Konvertierung" sollte noch funktionieren. – KeithS

+0

Ja, die Konstruktor-basierte Version ist die Route, die Sie für jetzt gewählt haben. Ich werde versuchen, den anderen Weg zu finden, um eine explizite Konvertierung vom Basisbenutzer in den abgeleiteten SalesUser zu ermöglichen. Danke für Ihre Hilfe. – jaressloo

Verwandte Themen