2011-01-06 8 views
1

Lets sagen, dass ich die folgende Klassenstruktur in meiner Datenzugriffsschicht haben:Wie kann ich Ref-Parameter umgehen, die keine Typvariationen zulassen?

interface IBehavior<in T> 
{ 
    void Load(T model); 
} 

class ModelManager<T> 
{ 
    ModelManager(IEnumerable<IBehavior<T>> behaviors) { ... } 

    void Load(T model) 
    { 
    foreach (var behavior in behaviors) { 
     behavior.Load(model) 
    } 
    } 
} 

Das bin ich verschiedene Schnittstellen können, die meine Modelle umsetzen können, und wiederverwendbare Verhaltensweisen, die diese Schnittstellen handhaben:

interface IUnique { ... } 
class UniqueBehavior : IBehavior<IUnique> { ... } 

interface ITimestampable { ... } 
class TimestampableBehavior : IBehavior<ITimestampable> { ... } 

Und der Manager nimmt diese wegen der Kontravarianz gerne in IBehavior<T>.

class MyModel : IUnique, ITimestampable { ... } 

new ModelManager<MyModel>(new IBehavior<MyModel>[] { 
    new UniqueBehavior(), 
    new TimestampableBehavior() 
}); 

Super.

Aber jetzt möchte ich, dass jedes Verhalten einen Satz von LINQ-Filtern auch auf die Entität anwendet. Meine erste Idee war, diese Methode zu IBehavior<T> hinzuzufügen:

void ApplyFilters<IEnumerable>(ref IEnumerable<T> models) 

... in dem ein Durchführungsverhalten eine Reihe von Where Klauseln in die Aufzählung nach eigenem Ermessen anwenden würde.

Wie sich jedoch herausstellt, ref parameters don't allow type variation. Ich bemühe mich, einen Weg zu finden, um diese Art von Funktionalität zu implementieren, während ich sowohl die Typsicherheit als auch die kontravariante Natur der Schnittstelle beibehalte. Irgendwelche Ideen werden geschätzt.

+1

Ich würde 'ApplyFilters' erwarten, die Unterschrift zu haben IEnumerable ApplyFilters (IEnumerable Modelle)' – Gabe

+0

Würde auch nicht funktionieren, macht es T ein Rückgabetyp. Ich erinnere mich, beides zu versuchen, und in meinem Fall macht die Verwendung von ref mehr Sinn. Auf diese Weise kann das Verfahren leer bleiben, wenn das Verhalten keine Filter anwenden möchte. –

Antwort

1

Nicht sicher, ob dies in Ihrem genauen Kontext funktionieren würde, aber haben Sie versucht, ApplyFolder generisch zu machen?

void ApplyFolders<TEnum>(ref IEnumerable<TEnum> models) where TEnum : T; 
+0

Das ist so verrückt, dass es funktioniert! Danke, daran hätte ich selbst nicht gedacht. –

+0

Es ist ein Trick, den ich benutze, wenn ich .NET 4 generische Varianz nicht verwenden kann – thecoop

+0

Sie wahrscheinlich * wollen nicht einen 'ref' Parameter. – Gabe

1

Ich würde einen Blick auf die Ptr class werfen. Ich habe diese Klasse kürzlich ausgenutzt, um alle Einschränkungen vollständig zu überwinden. .NET setzt Ref-Keywords, damit ich Objekte, von denen die CLR aus irgendeinem Grund kein Recht hat, zu Nebeneffekten machen kann.

+0

Das ist eine großartige Klasse, aber es würde in diesem Fall nicht funktionieren, weil es nicht das Problem der Kontravarianz umgeht - die Eigenschaft wäre sowohl rein als auch raus. –

+0

Die Einschränkungen für "ref" dienen dazu, die Typensicherheit und Überprüfbarkeit zu gewährleisten; Denken Sie daran, dass 'ref 'bedeutet, dass die tatsächliche' äußere 'Variable geändert wird, keine Kopie, und Sie nicht möchten, dass die Instanz von einem anderen Thread unter Ihnen geändert wird ... – thecoop

+0

@LLia und @thecoop verwenden den PTR Klasse haben Sie ref-Verwendung, die Sie die zugrunde liegende Variable ändern können, ohne das Ref-Schlüsselwort zu verwenden. Diese Klasse funktioniert tatsächlich. Ich benutze dies, um die ref-Nutzung in einer Ertragsmethode zu verwenden. Bei Methoden mit Rendite-Rückgabe können Sie keine ref-Variablen verwenden. –

Verwandte Themen