C# 反射、发射和实例化

C# 反射、发射和实例化,c#,.net-3.5,reflection.emit,C#,.net 3.5,Reflection.emit,我有一个集合和一些类。我要做的是创建一个类的实例,并以一种通用的方式填充它的属性,比如: public T FillObject(IDictionary<string,object> values) { /// CREATE INSTANCE /// FILL THE PROPERTIES WITH THE VALUES } public T FillObject(IDictionary值) { ///创建实例 ///用值填充属性 } 反射是最好的方法,但是它太慢

我有一个集合和一些类。我要做的是创建一个类的实例,并以一种通用的方式填充它的属性,比如:

public T FillObject(IDictionary<string,object> values)
{
    /// CREATE INSTANCE
    /// FILL THE PROPERTIES WITH THE VALUES
}
public T FillObject(IDictionary值)
{
///创建实例
///用值填充属性
}
反射是最好的方法,但是它太慢了,相反,我听说Reflection.Emit更快,那么,有没有方法实例化类并用Reflection.Emit填充其属性

提前感谢您的帮助。

这样做。这是一个微型ORM,用来驱动stackoverflow。整个ORM只是一个C#文件

创建动态方法的相关代码如下:

var method = new DynamicMethod(commandType.Name + "_BindByName", null, new Type[] { typeof(IDbCommand), typeof(bool) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Callvirt, setter, null);
il.Emit(OpCodes.Ret);
action = (Action<IDbCommand, bool>)method.CreateDelegate(typeof(Action<IDbCommand, bool>));
var method=newdynamicmethod(commandType.Name+“_BindByName”,null,新类型[]{typeof(IDbCommand),typeof(bool)});
var il=method.GetILGenerator();
il.Emit(操作码.Ldarg_0);
il.Emit(操作码.Castclass,命令类型);
il.Emit(操作码Ldarg_1);
EmitCall(OpCodes.Callvirt,setter,null);
发射(操作码Ret);
action=(action)方法.CreateDelegate(typeof(action));

还请注意,该项目提供了自己的实现,并提供了一些增强功能。如果你是白手起家的话,不妨把它作为一种选择;这就像是反思,但随着IL一代被抛在中间的表现;然后,您只需使用常规组件模型代码:

object obj = Activator.CreateInstance(typeof(T));
var props = TypeDescriptor.GetProperties(typeof(T));
foreach(var pair in data)
{
    props[pair.Key].SetValue(obj, pair.Value);
}
编辑;对于2012年的更新,涉及的抽象更少:

var accessor = TypeAccessor.Create(typeof(T));
foreach(var pair in data)
{
    accessor[obj, pair.Key] = pair.Value;
}

除了更加直接之外,FastMember还可以正确地处理
动态
类型,而不仅仅是反射。

如果您使用的是.Net 4,您可以使用新的
表达式
类型(添加来支持
动态
),创建一个表达式来分配属性,将其编译到一个委托,反复地打电话。性能应与使用Reflection.Emit相当

class ObjectFiller<T>
{
    private static Func<IDictionary<string, object>, T> FillerDelegate;

    private static void Init()
    {
        var obj = Expression.Parameter(typeof(T), "obj");
        var valuesDictionary = Expression.Parameter(typeof(IDictionary<string, object>), "values");

        var create = Expression.Assign(
            obj, Expression.Call(typeof(Activator), "CreateInstance", new[] { typeof(T) }));

        var properties = typeof(T).GetProperties();

        var setters = Expression.Block(properties.Select(p => CreateSetter(p, obj, valuesDictionary)));

        var methodBody = Expression.Block(typeof(T), new[] { obj }, create, setters, obj);

        var fillerExpression = Expression.Lambda<Func<IDictionary<string, object>, T>>(methodBody, valuesDictionary);

        FillerDelegate = fillerExpression.Compile();
    }

    static Expression CreateSetter(PropertyInfo property, Expression obj, Expression valuesDictionary)
    {
        var indexer = Expression.MakeIndex(
            valuesDictionary,
            typeof(IDictionary<string, object>).GetProperty("Item", new[] { typeof(string) }),
            new[] { Expression.Constant(property.Name) });

        var setter = Expression.Assign(
            Expression.Property(obj, property),
            Expression.Convert(indexer, property.PropertyType));

        var valuesContainsProperty = Expression.Call(
            valuesDictionary, "ContainsKey", null, Expression.Constant(property.Name));

        var condition = Expression.IfThen(valuesContainsProperty, setter);

        return condition;
    }

    public T FillObject(IDictionary<string, object> values)
    {
        if (FillerDelegate == null)
            Init();
        return FillerDelegate(values);
    }
}
类ObjectFiller
{
专用静态函数FillerDelegate;
私有静态void Init()
{
var obj=表达式参数(类型(T),“obj”);
var valuesDictionary=表达式.参数(类型化(IDictionary),“值”);
var create=Expression.Assign(
obj,Expression.Call(typeof(Activator),“CreateInstance”,new[]{typeof(T)});
var properties=typeof(T).GetProperties();
var setters=Expression.Block(properties.Select(p=>CreateSetter(p,obj,valuesDictionary));
var methodBody=Expression.Block(typeof(T),new[]{obj},create,setters,obj);
var filleexpression=Expression.Lambda(methodBody,valuesDictionary);
FillerDelegate=fillerExpression.Compile();
}
静态表达式CreateSetter(PropertyInfo属性、表达式对象、表达式值字典)
{
var indexer=Expression.MakeIndex(
价值观,
typeof(IDictionary).GetProperty(“Item”,新[]{typeof(string)}),
新[]{Expression.Constant(property.Name)});
var setter=Expression.Assign(
表达式.属性(obj,属性),
Convert(索引器,property.PropertyType));
var valuesContainsProperty=Expression.Call(
valuesDictionary,“ContainsKey”,null,Expression.Constant(property.Name));
var condition=Expression.IfThen(valuesContainsProperty,setter);
返回条件;
}
公共T FillObject(IDictionary值)
{
如果(FillerDelegate==null)
Init();
返回FillerDelegate(值);
}
}

您也可以在.NET3中使用对象初始值设定项的
表达式
版本执行类似的操作。

下面是一篇关于如何从数据库IDatarecord进行映射的示例文章。 这很容易适应大多数情况

动态的。。。但是很快:三只猴子、一只狼的故事,以及动态方法和ILGenerator类

请注意,我们的优势在于数据网格往往具有相同的列—字典映射不一定如此;类似的方法也可以,但会更复杂,因为它需要打开键。@Marc Gravell,没错,但如果要创建
T
的实例,那么字典键可能是相同的。除此之外,映射键不是问题的一部分。:-)最后,Dapper.NET真的很棒,所以任何炒作它的机会都是好的。我希望更多的框架会使用Reflection.Emit而不是普通的旧反射。不过,有一些中间选项(dapper确实非常专业;我不确定我会在这里使用它作为比较…@Marc gravel,这是真的)。在我们的应用程序中,我们实际上在编译时生成构建器。在运行时更容易操作,速度更快。如果可以在编译时定义类,那么就没有理由不能生成特定于类的生成器。我以前从未见过这种情况。非常好。谢谢Marc,这是最好的解决方案。这个链接已经失效了,你有没有可能找到替代方案?