mortb
mortb

Reputation: 9869

Func to get the property instead of just the value

Is it possible to input an object and a second parameter to a method so that the second parameter can be used (without using strings and reflection) to get the a property of the object and use the property to both read and write the value?

I've written two methods below that I can use but each one has drawbacks. The first DoStuff is typesafe ("good") but it needs three parameters ("bad"). The second needs two parameters (optimal), but it is not typesafe ("bad") as it relies on a string to specify the property. Maybe there is some solution using Expression that I have not thought of?

Background: The usecase is that I want to be able to "extend" the value of any object (in my case I have lists of objects from several object reposites and these objects may have serveral properties containing userids as strings. another repository conatins the users and I want add info about the user to the strings in the previous repositories)

public class Foo
{
    public string Bar {get; set;}
}

void Main()
{
    var x = new Foo { Bar = "hello" };
    Console.WriteLine(x.Bar); // prints "hello"

    // the second paramter (Func<..>) gets the value, the third parameter Action<...>) sets the value
    DoStuff(x, y => y.Bar, (z, val) => z.Bar = val);
    Console.WriteLine(x.Bar); // prints "hello  goodbye"

    // just one parameter to get the property, but I would like this to be more type safe, preferably a Func
    DoStuff2(x, nameof(x.Bar));
    Console.WriteLine(x.Bar); // prints "hello  goodbye again"
}

public void DoStuff<T>(
    T obj, 
    Func<T, string> getProp, 
    Action<T, string> setProp)
{
    var x = getProp(obj);
    setProp(obj, x + " goodbye");
}

public void DoStuff2<T>(
    T obj, 
    string propName)
{
    var propInfo = typeof(T).GetProperty(propName);
    var currValue = propInfo.GetValue(obj) as string;
    propInfo.SetValue(obj, currValue + " again");
}

Upvotes: 0

Views: 307

Answers (1)

Alen.Toma
Alen.Toma

Reputation: 4870

Well i did something like that awhile ago. here is an example:

 public void SetValue<T, TP>(T obj, Expression<Func<T, TP>> action, TP value) where T : class
 {
      var member = action.Body is UnaryExpression 
                 ? ((MemberExpression)((UnaryExpression)action.Body).Operand) 
                 : (action.Body is MethodCallExpression 
                     ? ((MemberExpression)((MethodCallExpression)action.Body).Object) 
                     : (MemberExpression)action.Body);

     var key = member?.Member.Name;
     typeof(T).GetProperty(key).SetValue(obj, value);

 }

You call it like this.

SetValue<User>(x=> x.UserName, "Admin");

Upvotes: 1

Related Questions