C# 动态类型初始值设定项

发布于 2024-08-22 14:15:46 字数 622 浏览 12 评论 0原文

我正在尝试动态构建类似 C# 类型初始化器的东西:

MyClass class = new MyClass { MyStringProperty= inputString };

我想构建一个泛型方法,该方法对给定类型进行一次反射并返回一个委托,该委托创建该类的新实例并根据输入参数填充它。方法签名可能如下所示:

Func<string,T> CreateFunc<T>();

调用结果函数将创建一个新的“T”实例,其中(例如)每个 String 类型的公共属性的值为输入字符串参数的值。

因此,假设“MyClass”只有 MyStringProperty,下面的代码在功能上与开头的代码等效:

var func = CreateFunc<MyClass>();
func.Invoke(inputString);

我非常熟悉 System.Reflection 和 System.Linq.Expressions 命名空间,并且我已经完成了一些中等复杂的工作过去这样的事情,但这一次让我难住了。我想构建一个已编译的委托,而不是简单地使用反射迭代属性。

谢谢!

I'm trying to build something like the C# type initalizer dynamically:

MyClass class = new MyClass { MyStringProperty= inputString };

I want to build a generic method that reflects over a given type once and returns a delegate which creates a new instance of the class and populates it based on the input parameter. The method signature might look like this:

Func<string,T> CreateFunc<T>();

And calling the resulting function would create a new instance of 'T' with (for example) every public property with of type String to the value of the input string argument.

So assuming that 'MyClass' has only MyStringProperty, the code below would be functionally equivalent to the code at the beginning:

var func = CreateFunc<MyClass>();
func.Invoke(inputString);

I'm pretty familiar with the System.Reflection and System.Linq.Expressions namespaces, and I've done some moderately complex things like this in the past, but this one has me stumped. I want to build a compiled delegate, not simply iterate through the properties using reflection.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罗罗贝儿 2024-08-29 14:15:46

在 CLR 4.0 中,您将能够使用表达式构建完整的语句。

在那之前,您正在寻找一份代码生成工作。最快的原型制作方法是在 StringBuilder 中构建 C#,然后在其上调用编译器。有了缓存,它会表现得很好。

最核心的方法是生成 IL 并使用 Reflection Emit 来构建方法,从而避免调用编译器。

In CLR 4.0 you'll be able to build complete statements with Expressions.

Until then, you're looking at a code-gen job. The quickest way to prototype it would be by building C# in a StringBuilder and then calling the compiler on it. With caching it would perform okay.

The hardcore way to do it would be to generate the IL and use Reflection Emit to build the method, thus avoiding calling out to the compiler.

意犹 2024-08-29 14:15:46

呃,是的,所以我只是让事情变得对自己来说太复杂了。这是我一直在寻找的方法:

public static Func<string, T> CreateFunc<T>()
    where T : class
{
    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
    var param = Expression.Parameter(typeof(string),"o");
    var constructorInfo = typeof(T).GetConstructor(new Type[] { });
    List<MemberBinding> bindings = new List<MemberBinding>();
    foreach (var property in properties)
        bindings.Add(Expression.Bind(property, param));

    var memberInit = Expression.MemberInit(Expression.New(constructorInfo), bindings);

    var func = Expression.Lambda<Func<string, T>>(memberInit, new ParameterExpression[] {param}).Compile();

    return func;            
}

Uh, yeah so I was just making things way too complicated for myself. This is the method I was looking for:

public static Func<string, T> CreateFunc<T>()
    where T : class
{
    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
    var param = Expression.Parameter(typeof(string),"o");
    var constructorInfo = typeof(T).GetConstructor(new Type[] { });
    List<MemberBinding> bindings = new List<MemberBinding>();
    foreach (var property in properties)
        bindings.Add(Expression.Bind(property, param));

    var memberInit = Expression.MemberInit(Expression.New(constructorInfo), bindings);

    var func = Expression.Lambda<Func<string, T>>(memberInit, new ParameterExpression[] {param}).Compile();

    return func;            
}
栩栩如生 2024-08-29 14:15:46

不幸的是,我没有看到这种情况发生,尽管我不是使用表达式和委托进行的深度巫术方面的专家。

在我看来,你只能通过反思来做到这一点。如果没有反射,您需要在编译时知道要设置的每个属性的名称是什么。您可以为您想要支持的每个单独的类执行单独的函数,但这似乎违背了通用的、一刀切的函数的要求。

我可以问一下为什么要使用这个功能吗?某种形式的依赖注入?

Unfortunately, I don't see this happening, although I'm no expert when it comes to the deep vodoo you can do with expressions and delegates.

The way I see it, you can only do this with reflection. Without reflection, you need to know at compile time what the names of each property you want to set are. You could do individual functions for each separate class you wanted to support, but that seems counter to the requirement of a generic, one-size-fits-all function.

May I ask why the function in the first place? Some form of dependency injection?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文