【问题标题】:How can I get a reference to a property's setter?如何获取对属性设置器的引用?
【发布时间】:2011-04-13 00:15:38
【问题描述】:

我有一些 asp.net 代码用来自已发布表单的值填充 LINQ to SQL 对象(所有字符串字段)中的字段:

            userSelections.A = Request.Form["A"];
            userSelections.B = Request.Form["B"];
            userSelections.C = Request.Form["C"];
            userSelections.D = Request.Form["D"];

我想将表单字段的名称和关联的 setter 对象存储在一个表中,这样我就可以遍历整个集合,而无需编写一堆重复的代码。

有没有办法让一个委托给一个属性设置器?即,假设我有类 myClass,具有字符串属性 myProperty。我可以得到一个委托,比如 void myPropertySetterDelegate(string val, MyClass this),它可以与类的任何实例一起使用吗?

我知道这可以通过反射来完成,但我项目中的其他开发人员有性能问题,所以如果可能的话,我更喜欢非反射解决方案。

谢谢!

【问题讨论】:

  • 也许如果您发布了一些您试图避免的重复代码,那么有人将能够更好地看到您正在尝试做什么。
  • 类似问题:onetwothree
  • 顺便说一句,没有必要在标题中加上“C#”,因为您已经在标签中找到了它。

标签: c# .net asp.net


【解决方案1】:

您可以使用 lambda:

Action<MyClass, string> myPropertySetter = (mc, s) => mc.MyProperty = s;

你有一个MyClass的实例:

MyClass something = repo.GetMyClass();
myPropertySetter(something, valueFromSomewhere);

现在,按照你的例子:

Dictionary<string, Action<MyClass, string>> setters = new Dictionary<string, Action<MyClass, string>>();
setters.Add("A", Action<MyClass, string> myPropertySetter = (mc, s) => mc.A = s);
[...]

稍后:

MyClass something = getFromSomewhere();
foreach (string key in Request.Form.Keys)
{
  setters[key](something, Request.Form[key]);
}

【讨论】:

  • 这只是让我们回到得分 #1:您必须手动将每个属性添加到您的 setters 字典中,这似乎是 OP 试图避免的。
  • 这可以在 Web 应用程序启动时完成,之后就不需要了。你必须死一死才能实现这一目标。
  • 是的,您必须至少编写一次代码才能执行,这很明显。 OP 正在寻求一种方法来避免对一堆作业进行硬编码。该代码在哪里并不重要。他不想为每个“选择”对象编写它。幸运的是,有一种方法可以做到这一点,我在回答中对此进行了描述。
【解决方案2】:

您可以使用反射来获取有关您尝试绑定到请求的类型的信息,然后生成动态方法(应该缓存它们以重用)以使执行速度非常快。

    public static Action<object, object> CreateSetter(FieldInfo field)
    {
        DynamicMethod dm = new DynamicMethod("DynamicSet", typeof(void),
            new Type[] { typeof(object), typeof(object) }, field.DeclaringType, true);

        ILGenerator generator = dm.GetILGenerator();

        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Ldarg_1);
        if (field.FieldType.IsValueType)
            generator.Emit(OpCodes.Unbox_Any, field.FieldType);
        generator.Emit(OpCodes.Stfld, field);
        generator.Emit(OpCodes.Ret);

        return (Action<object, object>)dm.CreateDelegate(typeof(Action<object, object>));
    }

【讨论】:

  • 谢谢,最终选择了这个!
【解决方案3】:

this answer复制:

Action<int> valueSetter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), tc, tc.GetType().GetProperty("Value").GetSetMethod());

是的,这使用反射,但它会产生更高性能的委托。此外,“反思”和“不反思”之间并没有明确的界限。比如Delegate类型自带了很多接受Type的方法,而Type本质上是由反射构成的。那么Delegate 是否使用反射?

【讨论】:

    【解决方案4】:
    Action<string, MyClass> propertySetter = (val, @this) => { @this.Property = val; }
    

    【讨论】:

      【解决方案5】:
      猜你喜欢
      • 2012-12-29
      • 2014-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-11
      • 2015-06-23
      • 1970-01-01
      相关资源
      最近更新 更多