Das Problem ist, dass Sie die string
Ergebnistyp aus der Eigenschaft, aber Sie müssen ihn trotzdem in den Typargumenten angeben, weil Sie auch die Product
.
Eine gute Möglichkeit, dies zu erreichen, wäre ein typisierter Datensatz:
IDataRecord<Product> productRecord = ...;
string name = productRecord.ReadValue(p => p.Name);
Dies scheint machbar zu sein, denn in einem ORM-Kontext wie dem, den Sie meinen, sollten Sie den von einem Datensatz repräsentierten Datentyp kennen.
Der schwierige Teil ist die ...
im obigen Code. Er erfordert eine gewisse Infrastruktur, aber Sie müssen ihn nur einmal schreiben und können ihn überall verwenden. Der erste Schritt besteht darin, den typisierten Datensatz abzuleiten:
public interface IDataRecord<T> : IDataRecord
{
TValue GetValue<TValue>(Expression<Func<T, TValue>> getter);
}
Als nächstes implementieren Sie den getippten Datensatz mit der Dekorationsmuster (langweilig, aber einfach):
public class DataRecord<T> : IDataRecord<T>
{
private readonly IDataRecord _untypedRecord;
public DataRecord(IDataRecord untypedRecord)
{
_untypedRecord = untypedRecord;
}
public TValue GetValue<TValue>(Expression<Func<T, TValue>> getter)
{
...the original code...
}
...pass through all other members to the untyped record...
}
Schließlich fügen Sie eine Transformation vom untypisierten zum typisierten Datensatz hinzu:
public static class TypedDataRecords
{
public static IDataRecord<T> TypedAs<T>(this IDataRecord untypedRecord)
{
return new DataRecord<T>(untypedRecord);
}
}
Das Beispiel sieht folgendermaßen aus:
IDataRecord<Product> productRecord = record.TypedAs<Product>();
string name = productRecord.ReadValue(p => p.Name);
decimal price = productRecord.ReadValue(p => p.Price);
...