Reputation: 9869
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
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