2015-02-13 6 views
6

Bei dieser Frage geht es um die Angabe generischer Typspezifikationsargumente. Es ist ein bisschen lang, also bitte ertragen Sie es.Generische Typspezifikationsargumente - manchmal optional, aber nicht immer

Wenn Sie die folgenden (erfundene) Klassen haben ...

public abstract class UserBase 
{ 
    public void DoSomethingWithUser() { } 
} 

public class FirstTimeUser : UserBase 
{ 
    /* TODO: some implementation */ 
} 

Die folgende Methode ...

private static void DoThingsWithUser<TUser>(TUser user) where TUser : UserBase 
{ 
    user.DoSomethingWithUser(); 
} 

Kann mit oder ohne auf den Typ Argument TUser aufgerufen werden. ..

var user = new FirstTimeUser(); 

DoThingsWithUser<FirstTimeUser>(user); 
DoThingsWithUser(user); // also valid, and less typing required! 

So weit, so gut.

Aber wenn Sie ein paar mehr hinzuzufügen (auch hier erfundene) Klassen ...

public abstract class UserDisplayBase<T> where T : UserBase 
{ 
    public T User { get; protected set; } 
} 

public class FirstTimeUserDisplay : UserDisplayBase<FirstTimeUser> 
{ 
    public FirstTimeUserDisplay() 
    { 
     User = new FirstTimeUser(); 
    } 
} 

und ein Verfahren ...

private static void DoThingsWithUserDisplay<TDisplay, TUser>(TDisplay userDisplay) 
    where TDisplay : UserDisplayBase<TUser> 
    where TUser : UserBase 
{ 
    userDisplay.User.DoSomethingWithUser(); 
} 

Bei Aufruf dieser Methode ist es obligatorisch umfassen die Typargumente ...

var userDisplay = new FirstTimeUserDisplay(); 
DoThingsWithUserDisplay<FirstTimeUserDisplay, FirstTimeUser>(userDisplay); // Type arguments required! 

Wenn Sie nicht die Art a angeben rguments erhalten Sie einen Compilerfehler von

Die Typ Argumente für die Methode 'DoThingsWithUserDisplay (TDisplay)' kann nicht aus der Verwendung abgeleitet werden. Versuchen Sie, die Typargumente explizit anzugeben.

ich denken, dass der Compiler könnte/sollte klug genug sein, dies ... um herauszufinden, oder gibt es einen subtilen Grund, warum nicht?

+0

Meine Vermutung ist, genannt werden, dass der Compiler dies nicht für eine Schnittstelle tun könnte mit Co/Kontra, und sie nicht glaube, es hat sich gelohnt Sonder-Gehäuse, dass und es in anderen Situationen tun. –

+1

Dies * könnte * relevant sein: http: // stackoverflow.com/questions/8511066/warum-nicht-c-sharp-infer-my-generische-types –

+1

@MatthewWatson - definitiv eine verwandte Frage, aber ich wundere mich _why_ der Compiler nicht/kann nicht die Art Argumente abzuleiten. Was meiner Meinung nach etwas anders ist, um zu verhindern, dass meine Frage geschlossen wird. :) –

Antwort

2

Als Compiler die Typen analysiert zu folgern, es erreicht eine Sackgasse, wenn sie bei DoThingsWithUserDisplay(userDisplay);

suchen Sie findet, dass TDisplayFirstTimeUserDisplay vom Typ sein muss, was gut ist. Dann besagt die Einschränkung, dass TDisplay von UserDisplayBase<TUser> erben muss.

Da weiß er nicht der Typ für TUser kann es nicht bestimmen, ob FirstTimeUserDisplay erbt von UserDisplayBase<TUser> und es kann auch nicht daraus schließen, dass die TUser Parameter sollen unabhängig von der Art in den generischen UserDisplayBase<TUser> ist.

Bearbeiten: Übrigens können Sie die Typ-Inferenz, die Sie suchen, mit einer Schnittstelle mit einer Variante erhalten. In diesem Fall stellt die Schnittstellendefinition ausreichende Vererbungsinformationen bereit, damit die Einschränkungen erfüllt werden.

public abstract class UserDisplayBase<T> : IUserDisplayBase<T> 
    where T : UserBase 
{ 
    public T User { get; protected set; } 
} 

public interface IUserDisplayBase<out T> 
    where T : UserBase 
{ 
    T User { get; } 
} 

private static void DoThingsWithUserDisplay<TDisplay>(TDisplay userDisplay) 
    where TDisplay : IUserDisplayBase<UserBase> 
{ 
    userDisplay.User.DoSomethingWithUser(); 
} 

mit

var userDisplay = new FirstTimeUserDisplay(); 
DoThingsWithUserDisplay(userDisplay); 
Verwandte Themen