[ACCEPTED]-Is there any way to pass the setter of a property to a delegate?-properties

Accepted answer
Score: 11

The answer to your question is going to 37 be no. At least as far as C# is concerned.

Why? Let's 36 say that you have the following object:

public class Foo
{
    public int SomeProp { get; set; }
}

you 35 know that under the hood the compiler will 34 autogenerate int get_SomeProp() and void 33 set_SomeProp(int value) for you (plus the 32 backing field), so you should be able to 31 do this:

var someMethod = foo.get_SomeProp;

and you can - almost. You get this 30 error from the compiler: "cannot explicitly 29 call operator or accessor". So without 28 reflection or a wrapper, you're SOL. Maybe. I 27 say maybe because just because C# doesn't 26 let you treat a getter or setter like a 25 real method, it doesn't mean that some other 24 .NET language can't. For example, I can 23 write this in F#:

namespace PassSetter

module mucker =
    let muckWithFoo (aFoo:Foo) =
        aFoo.set_SomeProp

and now muckWithFoo is 22 a function declared as Foo->(int->unit), which 21 is equivalent to a method that returns delegate 20 void d(int value). In essence, you can 19 use another module to break the C# compiler 18 constraint, if need be. I picked F# only 17 because I have the compiler handy, but I 16 bet you could do this with C++/CLI as well.

The 15 main difference between this and a wrapper 14 is that even though you still need to write 13 a wrapper for every type for which you would 12 like to get a delegate from, that wrapper 11 doesn't end up attached to the final delegate.

I 10 don't know what your issue is with the "no 9 reflection" constraint - is it that you're 8 running in an environment that forbids reflection 7 or that you believe that you're so performance 6 bound that you can't afford to use reflection. If 5 it's the latter, then there are several 4 more options open to you that give you much 3 better performance than simply reflection 2 to get the property set method and then 1 invoke it (effectively call by name).

Score: 7

Define this helper function(You'll need 5 to add the error checking):

Action<TObject,TValue> GetSetter<TObject,TValue>(Expression<Func<TObject,TValue>> property)
{
    var memberExp=(MemberExpression)property.Body;
    var propInfo=(PropertyInfo)memberExp.Member;
    MethodInfo setter=propInfo.GetSetMethod();
    Delegate del=Delegate.CreateDelegate(typeof(Action<TObject,TValue>),setter);
    return (Action<TObject,TValue>)del;
}

And use it like 4 this:

Action<MyClass,int> setter=GetSetter((MyClass o)=>o.IntProperty);

This is not exactly what you want(It 3 uses reflection), but probably as close 2 as you'll get. The returned delegate is 1 the setter itself, no wrapper.

Score: 4

Why not use an interface?

interface IPropertySetter {
  string Property { set; }
}

Have your class 1 implement it:

class MyClass : IPropertySetter {
  public string Property { get; set; }
}

And pass it to your object:

var c = new MyClass();
myObject.MyMethod(c);

...

void MyMethod(IPropertySetter setter) {
  setter.Property = someValue;
  // you can also store the "setter" and use it later...
}
Score: 2

C# does not allow this (because of the specialname 5 attribute the compiler generates on the 4 set_AnotherProperty method), however J# would 3 because it does not support the property 2 syntax.

This is what the code would look like.

  Action<int> x = set_AnotherProperty(1);

However, the 1 C# compiler tells you

Error   3   'Program.AnotherProperty.set': 
cannot explicitly call operator or accessor
Score: 1

I am pretty sure the answer is no. The most 4 common approach to this is to use lambda 3 expressions, see for example the common 2 solution to hard-coded INotifyPropertyChanged 1 strings:

http://10rem.net/blog/2010/12/16/strategies-for-improving-inotifypropertychanged-in-wpf-and-silverlight

There are no other magic ways!

Score: 0

If you don't want to pass a wrapper around 4 a property's setter, you can go the other 3 way around and let the setter be a wrapper 2 around a method. For example:

public MyClass
{
    private Foo _myProperty;
    public Foo MyProperty
    {
        get { return _myProperty; }
        set { MyPropertySetter(value); }
    }

    public void MyPropertySetter(Foo foo)
    {
        _myProperty = foo;
    }
}

then do:

myObject.Mymethod(myOtherObject.MyPropertySetter);

It's 1 not pretty, but it does what you want done.

Score: 0

For your constraints, it seems you can't 9 use properties at all. If the performance 8 considerations are so strong that you can't 7 simply wrap the setter in a lambda, then 6 you might want to change your style of development. That's 5 normally what's done in extreme cases of 4 code tuning. Put on your Java hat and create 3 explicit setter and getter methods in your C# code:

class MyClass {
  private string _value;
  public void setProperty(string value) { _value = value; } 
} 

No properties 2 involved... But, how much that really buys you 1 over lambdas? I wouldn't think it's noticeable.

Score: 0

A property can be wrapped in a delegate, if 6 intellectual purity and lexical beauty are 5 not synonymous. Of course it is not quite 4 a property, with null being a trigger for 3 read/write operations and the need for the 2 'called' to treat it like a function, after 1 all.

xType1 xProperty1 {get;set;}

xType2 xProperty1 {get;set;}

xCallingFunction()
{
   ....
   xCalledFunction( 
     ((s)=> s == null ? xProperty1 : (xProperty1 = s)),
     ((s)=> s == null ? xProperty2 : (xProperty2 = s))
     );
   ....
}

....

xCalledFunction( Func<xType, xType> parm1, Func<xType2, xType2> parm2 )
   var p1 = parm1(null);
   parm2( newValue );
   parm1( parm1(null) + 16 );

More Related questions