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.
Ich würde 'ApplyFilters' erwarten, die Unterschrift zu haben IEnumerable ApplyFilters (IEnumerable Modelle)' –
Gabe
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. –