1

I would like to do something similar:

SetPropertyValue(ref class1.Sport, prop2);

private static void SetPropertyValue(ref Prop1 prop1, bool prop2)
{
    prop1 = new Prop1
    {
        BoolValue = prop2,
    };
}
Revious
  • 7,816
  • 31
  • 98
  • 147

3 Answers3

3

You can use Lambda Expressions and a method to call the setValue on the property.

Create this method:

public void SetPropertyValue<O, T>(O obj, Expression<Func<O, T>> property, T value)
{
    var memberSelectorExpression = property.Body as MemberExpression;
    if (memberSelectorExpression != null)
    {
        var p = memberSelectorExpression.Member as PropertyInfo;
        if (p != null)
        {
            p.SetValue(obj, value, null);
        }
    }
}

Then call it

SetPropertyValue(textBox1, (t=>t.BackColor), Color.Red );

See:

How to set property value using Expressions?

As Servy sugguests, performance may be an issue for you. You can also use a different technique described at CodeProject:

http://www.codeproject.com/Articles/584720/ExpressionplusbasedplusPropertyplusGettersplusandp

Community
  • 1
  • 1
Charlie
  • 8,530
  • 2
  • 55
  • 53
  • 1
    Of course you've not lost all compile time type safety, as the compiler won't tell you if the object isn't of a compatible type with the property, or if the property doesn't have a setter (that is accessible), you pay lots of expensive performance costs to get this dynamic typing, you can have things other than direct accesses to a property in the expression that cause everything to break, and so on. And all of this to do something that takes quite a bit *more* code to write than `textbox1.BackColor = Color.Red;`. – Servy Mar 28 '14 at 18:28
  • Servy, I think I've addressed your type safety concerns. – Charlie Mar 28 '14 at 18:34
  • You've addressed only one of many of the concerns that I mentioned. You still have all of the rest to get through. – Servy Mar 28 '14 at 18:35
  • 1
    The rest of your concerns are based on the assertion that the call to the SetPropertyValue method is sending in the lambda itself but it might actually be a parameter. Setting the property directly doesn't address the OP question or any search-engine viewers at all. Any attempt to throw an exception because the value is private is redundant with the runtime exception that would occur in the same vein. Do you have any evidence of this performances cost? – Charlie Mar 28 '14 at 18:43
  • 1
    There is nothing in the OP at all about getting the lambda as a parameter. He isn't doing that, nor is there any indication that he might need to. Yes, setting it directly *does* solve his exact problem. It does so very easily and effectively. Way more so than your solution. The whole *point* of my comment is that your code has all sorts of possible runtime exceptions that it can generate. Code with static type safety *will never, ever* have such exceptions, because the code wouldn't compile unless it was valid. You can trivially research reflection's performance costs. – Servy Mar 28 '14 at 18:48
  • 1
    The OP is explicitly asking for a method with the property as a parameter. I've ran a benchmark, you are correct that is definitely slower. Unless the OP is calling the method frequently, the performance is moot – Charlie Mar 28 '14 at 19:01
  • 1
    The performance difference is about 50x slower than setting the property directly. The 'slow way' takes ~10 seconds to set the background property of a textbox 1,000,000 times. – Charlie Mar 28 '14 at 19:08
  • 1
    So its slower, more fragile, more work to code, error prone when both coding and executing, and has literally *zero* advantages to offset those problems. And you still think it's a good solution? It has a ton of problems, and nothing to offset those problems. It's a poor solution to the problem. – Servy Mar 28 '14 at 19:08
  • 1
    It's only fragile for properties that are read-only. The non-zero advantage is that it answers the question the OP is asking for: a method to set a property using the property as a parameter to said method. I would hardly call a minor performance impact, incompatibility with accessors (which could just be added as an if statement to the method), and an unlikely read-only runtime exception (that could easily be handled) "a ton of problems". – Charlie Mar 28 '14 at 19:11
  • 1
    No, that's *not* the only case. You also have to deal with the possibility of the expression containing something other than *just* a property access. You need to deal with accessibility issues. You're potentially boxing both the instance and the value of the property. When someone asks how to drive a nail using a glass bottle you tell them to use a hammer, because that's the appropriate tool to use to drive nails. Giving advice on how to use a glass bottle to drive a nail is actively harmful. – Servy Mar 28 '14 at 19:18
  • What if someone asks "Which type of glass bottle should I use to drive a nail?" – Charlie Mar 28 '14 at 19:35
  • You tell them to go get a hammer, or possibly explain why it's important that they use a glass bottle instead of a hammer. If they explain that they're allergic to the polish that all hammers use on their handles, then a proper solution for driving nails (given whatever additional constraints) can be found (possibly, wear a glove), without resorting to using glass bottles. – Servy Mar 28 '14 at 19:44
  • Thanks for the very interesting discussion. If you are interested in my point of view, I believe Charlie's example is really interesting. But also Servy is right on many aspects. On the performance there is absolutely no issue unless it's on a for cycle of million of elements. If performance would matter we would not use c# but c++ or assembly or, better, logical networks. Also, company seldom use Profiler and the Relational Databases are thousand of times slower than a normal write to the hard drive. Nothing in the software IT shows a real effort in performance direction. – Revious Mar 29 '14 at 02:09
2

Since you already have a strong reference to the property, you shouldn't need to "dynamically" set it. All you need to do is:

class1.Sport = CreateProp1(prop2);

private Prop1 CreateProp1(bool initialBoolValue)
{
   return new Prop1()
   {
      BoolValue = initialBoolValue;
   }
}

Even better would be to modify Prop1 to have a constructor that takes a bool:

public Prop1(bool initialBoolValue)
{
   BoolValue = initialBoolValue;
}

class1.Sport = new Prop1(prop2);
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
0

You can do it just like this:

class1.Sport = myProperty(property);