2015-12-29 17 views
6

Ich liebe Generika in C#, aber manchmal mit ihnen zu arbeiten kann ein bisschen kompliziert werden. Auf das Problem unten stoße ich hin und wieder. Gibt es eine Möglichkeit, dieses Szenario zu vereinfachen? Ich kann nicht sehen, wie, aber ich bin der Hoffnung, jemandIst es möglich, geschachtelte Generics in C# zu vereinfachen?

Bei drei Basisklassen kann :):

public abstract class Inner 
{ 
} 

public abstract class Outer<T> 
    where T : Inner 
{ 
} 

public abstract class Handler<TOuter, TInner> 
    where TOuter : Outer<TInner> 
    where TInner : Inner 
{ 
    public abstract void SetValue(TInner value); 
} 

Und einige einfache Implementierungen: meine Frage

public class In : Inner 
{ 
} 

public class Out : Outer<In> 
{ 
} 

public class HandleOut : Handler<Out, In> 
{ 
    public override void SetValue(In value) { } 
} 

Jetzt ist: Für HandleOut, der Typ von TInner ist durch den Typ "Out" gegeben, so gibt es eine Möglichkeit, die Definition von HandleOut zu etwas wie public class HandleOut : Handler<Out> zu vereinfachen und immer noch den inneren Typ als Parameter zuverwenden zu können?

Dies ist ein sehr einfaches Beispiel, aber manchmal bekomme ich eine lange Liste von generischen Typen in Definitionen, wenn normalerweise alle logisch vom ersten Typ abgeleitet werden können. Gibt es Tricks, die ich vermisse?

+2

Ich habe Ihren Code so korrigiert, dass er kompiliert wird. Kannst du bitte überprüfen, ob es im POV deiner Frage korrekt ist? – Enigmativity

+4

Sie stimmen zwar nicht zu 100% mit dem überein, was Sie sich fragen, aber vielleicht möchten Sie einen Blogeintrag von Eric Lippert mit dem Titel [Warum sind generische Constraints nicht vererbt?] Lesen (http://ericlippert.com/2013/07/15/ warum-sind-generische-constraints-not-geerbt /) (und in der Tat, die Tatsache, dass sie nicht geerbt sind, warum Enigmatismus Ihren Code reparieren musste, um * more * Einschränkungen hinzuzufügen) –

+0

Vielen Dank, @Enigmatismus. Ich habe den Code im Handumdrehen geschrieben - Ihre Änderungen entsprechen genau meinen Gedanken :) –

Antwort

1

Nr

Während solche Folgerung wohl möglich sein sollte, ist es ein Teil der languge nicht. Möglicherweise möchten Sie dies unter Roslyn vorschlagen (öffnen Sie eine neue Ausgabe). Natürlich kann diese Art von generischen Constraints Inferenz in komplexen Fällen zu Problemen führen, aber zumindest für die einfachen ist es machbar ... doch, wo sollte das C# -Team seine Zeit und Mühe investieren?

Der Link Why are generic constraints not inherited, dass Damien_The_Unbelievershared on the comments ist genau richtig.


Wie auch immer, in den Code Ihrer präsentiert, während es wahr ist, dass Out bereits geben Sie den Typ In, die generische Parameter TOuter ist nicht erforderlich.

Der folgende Code funktioniert genauso gut:

public abstract class Inner 
{ 
} 

public abstract class Outer<T> 
    where T : Inner 
{ 
} 

public abstract class Handler<TInner> // NOTE: TOuter removed 
    where TInner : Inner 
{ 
    public abstract void SetValue(TInner value); 
} 

public class In : Inner 
{ 
} 

public class Out : Outer<In> 
{ 
} 

public class HandleOut : Handler<In> // NOTE: Out removed 
{ 
    public override void SetValue(In value) { } 
} 

So betrachten kann Outer<TInner> statt touter verwenden, wenn Sie es brauchen. Natürlich, wenn Sie eine Liste von TOuter halten, wird es weniger restriktiv sein, da es jeden abgeleiteten Typ von Outer<TInner> anstelle von irgendeinem abgeleiteten Typ von TOuter erlauben wird.

Da Sie "neu" nicht in die generische Einschränkung eingefügt haben, erstellen Sie keine Objekte dieses Typs, aber wenn der Fall eintrifft, können Sie eine Func<Outer<TInner>> im Konstruktor akzeptieren.

+0

Vielen Dank für Ihre Antwort. Du hast Recht, dass ich den TOuter in meinem Beispiel verlieren könnte, aber das liegt nur daran, dass ich kein wirkliches Beispiel gegeben habe - ich würde den TOuter in meinen realen Fällen brauchen.Wenn das etwas ist, wofür die C# Zeit brauchen, bin ich mir nicht sicher. Vielleicht ist es nur meine Art zu schreiben, die mich oft in diese Art von Problem bringt, aber ich würde es sehr nützlich finden und eine sehr gute Abstraktion haben. Vielleicht etwas wie: öffentliche abstrakte Klasse Handler wo ...? –

+0

@ChrisRidge, dass die Syntax funktioniert, aber kaum mit der Art und Weise, wie das System derzeit ausgeführt wird, da jeder generische Parameter, der implizit ist oder nicht, verloren geht. Deshalb sehe ich es als Rückschluss auf den abgeleiteten Typ. Wie viele generische Parameter haben Sie? [Ich kann keinen Fall für mehr als 4 denken] Vielleicht ist es ein Vorteil dessen, was du entwickelst, oder vielleicht vermisst du etwas Abstraktion ... Aber wenn es einen bestimmten Fall erleichtert, gibt es vielleicht Interesse vom Roslyn-Team. Betrachten Sie optional - es ist nicht wirklich notwendig, aber es erleichtert die Wartung von Interop und Code. – Theraot

+0

In meinem aktuellen Projekt habe ich nicht mehr als vier selbst, aber diese sind in Schnittstellen, die oft implementiert sind. Die Angabe aller vier Typen für jede Implementierung ist mühsam und macht den Code schwieriger zu verstehen. Dies ist absolut kein Muss, aber für uns wäre es ein großartiges Feature :) –

Verwandte Themen