8

I have some asp.net code that populates the fields in a LINQ to SQL object (all string fields) with values from a posted form:

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

I want to store the name of the form field and the associated setter object in a table, so I can iterate through the whole set without having to write a bunch of repeating code.

Is there a way to get a delegate to a property setter? i.e., say I have class myClass, with string property myProperty. Can I get a delegate, something like void myPropertySetterDelegate(string val, MyClass this), that can be used with any instance of the class?

I know this can be done with reflection, but other developers on my project have performance concerns, so I would prefer a non-reflection solution if possible.

Thanks!

Femaref
  • 60,705
  • 7
  • 138
  • 176
nw.
  • 4,795
  • 8
  • 37
  • 42
  • Perhaps if you posted some of the repeating code that you are trying to avoid, someone would be able to better see what you are trying to do. – Fantius Apr 13 '11 at 00:20
  • Similar questions: [one](http://stackoverflow.com/questions/2823236/creating-a-property-setter-delegate), [two](http://stackoverflow.com/questions/4085798/creating-an-performant-open-delegate-for-an-property-setter-or-getter), [three](http://stackoverflow.com/questions/289980/is-there-a-delegate-available-for-properties-in-c) – Roman Starkov Apr 13 '11 at 00:28
  • BTW, it's not necessary to put "C#" in the title, since you've already got it in the tags. – John Saunders Apr 13 '11 at 00:33

5 Answers5

7

You can use a lambda:

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

And you have an instance of MyClass:

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

Now, following your example:

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

Later:

MyClass something = getFromSomewhere();
foreach (string key in Request.Form.Keys)
{
  setters[key](something, Request.Form[key]);
}
Femaref
  • 60,705
  • 7
  • 138
  • 176
  • this just brings us back to score #1: you have to add each property manually to your `setters` dictionary, which seems like what OP is trying to avoid. – Ilia G Apr 13 '11 at 00:30
  • Which can be done at startup of the web application and won't be needed afterwards. You have to die one death to achieve this. – Femaref Apr 13 '11 at 00:42
  • yes you have to write code at least once for it to be executed, that much is obvious. OP is asking for a way to avoid hardcoding a bunch of assignments. Where that code is doesn't really matter. He does not want to write it for each "selections" object. Luckily there is a way to do it, which I described in my answer. – Ilia G Apr 13 '11 at 00:46
4

you can use reflection to get info about the type you trying to bind to request and then generate dynamic methods (should cache them to reuse) to make execution really fast.

    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>));
    }
Ilia G
  • 10,043
  • 2
  • 40
  • 59
1

Copying from this answer:

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

Yes, this uses reflection, but it results in a more performant delegate. Besides, there is no clear boundary between "reflection" and "not reflection". For example, the Delegate type comes with a lot of methods that accept Type, and Type is essentially made of reflection. So is using Delegate using reflection or not?

Community
  • 1
  • 1
Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
0
Action<string, MyClass> propertySetter = (val, @this) => { @this.Property = val; }
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
0

Did you think about extension methods?

http://msdn.microsoft.com/en-us/library/bb311042.aspx http://msdn.microsoft.com/en-us/library/bb383977.aspx

Subhash Dike
  • 1,836
  • 1
  • 22
  • 37