Generics 使用lambda表达式和泛型编写此方法的更好方法

Generics 使用lambda表达式和泛型编写此方法的更好方法,generics,lambda,c#-3.0,extension-methods,Generics,Lambda,C# 3.0,Extension Methods,我需要一种从IDataRecord检索数据的方法,而不必使用恼人的“魔术字符串”来表示字段名。 经过一些研究,我提出了这种扩展方法: public static T2 ReadValue<T1, T2>(this IDataRecord record, Expression<Func<T1, T2>> expression) { MemberExpression body = (MemberExpression)expression.Body;

我需要一种从IDataRecord检索数据的方法,而不必使用恼人的“魔术字符串”来表示字段名。 经过一些研究,我提出了这种扩展方法:

public static T2 ReadValue<T1, T2>(this IDataRecord record, Expression<Func<T1, T2>> expression)
{
    MemberExpression body = (MemberExpression)expression.Body;
    string fieldName = body.Member.Name;
    int ordinal = record.GetOrdinal(fieldName);
    return (T2)(record.IsDBNull(ordinal) ? default(T2) : record.GetValue(ordinal));
}
publicstatict2readvalue(此IDataRecord记录,表达式)
{
MemberExpression body=(MemberExpression)expression.body;
字符串fieldName=body.Member.Name;
int ordinal=record.GetOrdinal(字段名);
return(T2)(record.IsDBNull(ordinal)?默认值(T2):record.GetValue(ordinal));
}
然后我用这样的方法:

product.Name = record.ReadValue<Product, string>(p => p.Name);
product.Name=record.ReadValue(p=>p.Name);
有没有其他方法可以简化这种方法?我喜欢这种行为,但不喜欢这种风格!:)

非常感谢你

也许这会起作用(我没有测试):


名称只指定一次,编译器推断泛型类型。显然,T1需要是一个引用类型。

问题是,您可以从属性推断
字符串
结果类型,但仍然必须在类型参数中指定它,因为您还必须指定
产品

一种很好的方法是使用类型化数据记录:

IDataRecord<Product> productRecord = ...;

string name = productRecord.ReadValue(p => p.Name);
public interface IDataRecord<T> : IDataRecord
{
    TValue GetValue<TValue>(Expression<Func<T, TValue>> getter);
}
接下来,使用以下命令实现类型化数据记录(枯燥但简单):

公共类数据记录:IDataRecord
{
私有只读IDataRecord(非类型记录);
公共数据记录(IDataRecord非类型记录)
{
_untypedRecord=untypedRecord;
}
公共TValue GetValue(表达式getter)
{
…原始代码。。。
}
…将所有其他成员传递到非类型化记录。。。
}
最后,添加从非类型化记录到类型化记录的转换:

public static class TypedDataRecords
{
    public static IDataRecord<T> TypedAs<T>(this IDataRecord untypedRecord)
    {
        return new DataRecord<T>(untypedRecord);
    }
}
公共静态类TypedDataRecords
{
公共静态IDataRecord类型DAS(此IDataRecord非类型记录)
{
返回新的数据记录(非类型记录);
}
}
现在,示例如下所示:

IDataRecord<Product> productRecord = record.TypedAs<Product>();

string name = productRecord.ReadValue(p => p.Name);
decimal price = productRecord.ReadValue(p => p.Price);
...
IDataRecord productRecord=record.TypedAs();
string name=productRecord.ReadValue(p=>p.name);
十进制价格=productRecord.ReadValue(p=>p.price);
...

这个问题更适合你。对不起,我不知道代码审查。你能移动我的问题吗?我不认为隐藏你正在使用魔术串的事实,而仍然使用魔术串,是对使用魔术串的改进。我在这里没有看到任何魔术串。所有表达式都完全支持重构。我遗漏了什么吗?没关系,我看错了。这很好用,但我并不总是有真正的产品。例如,我可以编写“return record.ReadValue(p=>p.ProductID);”而不需要Product类的实例。否则这将是一个绝妙的解决方案!这是一个有趣的方法。。。我会尽力给你我的反馈!我试图实现这个解决方案,但对于我的应用程序来说,这是一个过度的操作(我需要从同一个IDataRecord中取出不同的实体,修改太多了)。但这是一个正确的答案,所以我会标记它!多谢各位@亚历山德罗:很遗憾,这个解决方案对你不起作用。我很高兴你从中得到了一些启示。从技术上讲,您可以将相同的
IDataRecord
实例类型化为不同的实体;我只是假设每个记录只有一个实体,但这不是一个硬性规定。此外,我将此作为一个一次性编写的通用工具编写,希望您和其他人能够在许多不同的上下文中使用它。希望你能在将来找到它的一些用途。是的,布莱恩,这非常鼓舞人心!谢谢你的帮助!
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...
}
public static class TypedDataRecords
{
    public static IDataRecord<T> TypedAs<T>(this IDataRecord untypedRecord)
    {
        return new DataRecord<T>(untypedRecord);
    }
}
IDataRecord<Product> productRecord = record.TypedAs<Product>();

string name = productRecord.ReadValue(p => p.Name);
decimal price = productRecord.ReadValue(p => p.Price);
...