2015-10-12 11 views
8

Angesichts der folgende Schnittstelle:öffnen Allgemein Constraint

public interface IQuerySpec<M> { } 

Ich würde gerne eine Verlängerung Methode wie folgt machen:

public static OrderedSortation<T> OrderBy<T, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec<?> { 
    //business as usual 
} 

ich einfach sicher sein T diese Art wollen, ist eine gewisse Variation von IQuerySpec<M> . Ich konnte die Erweiterungsmethode dann rufen Sie wie folgt vor:

public class Foo : IQuerySpec<int> { 
    public int SizeOfSailBoat {get; set;} 
} 

IQuerySpec<Foo> foo = new Foo {SizeOfSailBoat = 10}. 
var result = foo.OrderBy(f => f.SizeOfSailBoat); 

Die UDT Foo im obigen Beispiel bezeichnet wurde, aber mir egal, welche generischen Typparameter verwendet wird.

Gibt es eine Möglichkeit, dies zu tun?

Ich habe versucht, die folgenden:

public static OrderedSortation<T> OrderBy<T, M, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec<M> { 
    //business as usual 
} 

Die oben genannten Arbeiten, erfordert aber, dass die generischen Parameter explizit angegeben, um sich „OrderBy“ aufzurufen. Ich möchte die generischen Parameter nicht explizit angeben müssen.

Ich habe auch versucht diese:

public interface IQuerySpec {} 
public interface IQuerySpec<M> : IQuerySpec {} 

Mit diesen Schnittstellen kann ich dies dann tun:

public static OrderedSortation<T> OrderBy<T, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec { 
    //business as usual 
} 

Dies ist fast gut genug, mit der Ausnahme, dass ich die nicht-generic IQuerySpec ausblenden möchten so dass es außerhalb meiner Klassenbibliothek nicht sichtbar ist. Ich würde gerne, wenn ich die nicht-generische Schnittstelle auf diese Weise scoped haben könnte:

internal interface IQuerySpec {} 

Leider wird der Compiler nicht lassen Sie mich das tun.

Ich rate, was ich will, ist nicht möglich, aber nur für den Fall zu fragen.

+0

Können Sie ein Beispiel geben, wie die Syntax der Verwendung aussehen soll? –

+0

@Mike: Ich habe ein Aufrufbeispiel hinzugefügt. –

Antwort

0

Das Problem ist, dass der Compiler nicht implizit den Typ von M von T oder T von M ableiten kann.

so müssen Sie ein fixieren, hier feste I T zu IQuerySpec<M>

und die Signatur der Methode Erweiterung wird

public static OrderedSortation<IQuerySpec<M>> OrderBy<M, TKey>(
    this IQuerySpec<M> query, 
    Expression<Func<IQuerySpec<M>, TKey>> sort) 

    { 
     //business as usual 
    } 

als Beispiel

class IntQSpec : IQuerySpec<int> 
    { 
     //your implementation 
    } 

und hier ist das Aufrufbeispiel

var iQS = new IntQSpec(); 
//do whatever you want with iQS 
var ord = iQS.OrderBy(ii=>ii.ToString()); 
//here I called OrderBy without the need to explicitly specifying the Generic Arguments 

hier der Test des Code auf Visual Studio 2013-2015, wo kein Fehler Notiz hervorgehoben, dass ich das Z-Feld von konkreter IntQSpec enter image description here

Ich hoffe, es zugegriffen wird helfen.

+0

Ich habe meine Frage geändert, um zu verdeutlichen, dass der Ausdrucksbaum in der Lage sein muss, auf Mitglieder des konkreten IQuerySpec zuzugreifen. In meinem Beispiel greife ich auf "SizeOfSailBoat" zu, das in der konkreten 'Foo'-Klasse verfügbar ist, aber nicht auf der IQuerySpec -Schnittstelle verfügbar ist. Das Beispiel, das Sie hier haben, wird nicht funktionieren. –

+0

ok, Wenn Sie Visual Studio 2010 und früher verwenden, dann schlägt der Compiler implizit, was Sie wollen, aber auf Visual Studio 2013-2015 arbeiten ohne Angabe der generischen Argumente – Aladdin

+0

Ich verwende VS 2015. In dem Beispiel, das Sie bereitgestellt haben , Sie übergeben 'M' in den Ausdrucksbaum. Der Ausdrucksbaum muss Zugriff auf "T" anstelle von "M" haben. –

0

Es scheint mir, dass IQuerySpec<M> entweder gar nicht benötigt und sollte nur sein IQuerySpec oder TKey sollte M immer sein auf das, was ich hier zu sehen. Ich vermute, dass ersetzt und damit IQuerySpec<M> mit IQuerySpec ist was Sie wirklich wollen basierend auf Ihrem Wunsch, dass Möffnen sein. Hier ist ein Beweis. Bitte sehen, ob sie paßt, was Sie versuchen, oder zu erreichen, wenn einer der Schritte auf dem Weg zur endgültigen Lösung näher:

Unter der Annahme, dass IQuerySpec<M> tatsächlich benötigt wird und M sollte immer gleich TKey die folgende compiliert und würde wahrscheinlich die Arbeit mit der Implementierung:

TKey Unter der Annahme M:

public interface IQuerySpec<M> { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey> 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec<int> { public int SizeOfSailBoat {get; set;} } 

Verbrauch:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
    } 
} 

Unter der Annahme, die Notwendigkeit für mehr TKey Optionen:

Wenn Sie andere Eigenschaften anderer Typen (Öffnung die Klasse für weitere Abfragen Möglichkeiten) unterstützen müssen, dann die Klasse, wie dies zum Beispiel aussehen könnte :

public interface IQuerySpec<M> { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey> 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec<int>, IQuerySpec<string> 
{ 
    public int SizeOfSailBoat {get; set;} 
    public string NameOfSailBoat {get; set;} 
} 

Verbrauch:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
     result = foo.OrderBy(f => f.NameOfSailBoat); 
    } 
} 

reduzieren IQuerySpec<M>-IQuerySpec:

In diesem Fall können Sie nur nur IQuerySpec wie dies mit vereinfachen könnte:

public interface IQuerySpec { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec 
{ 
    public int SizeOfSailBoat {get; set;} 
    public string NameOfSailBoat {get; set;} 
} 

Verbrauch:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
     result = foo.OrderBy(f => f.NameOfSailBoat); 
    } 
} 

Alle der oben genannten Arbeiten abgesehen, dass Für IQuerySpec sind keine Methoden- oder Eigenschaftensignaturen definiert, die sich aufbeziehen 10.