【问题标题】:Func to get the property instead of just the value函数获取属性而不仅仅是值
【发布时间】:2017-12-06 09:18:05
【问题描述】:

是否可以在方法中输入一个对象和第二个参数,以便第二个参数可以用来(不使用字符串和反射)获取对象的a属性,并使用该属性来读写价值?

我在下面编写了两种可以使用的方法,但每种方法都有缺点。第一个 DoStuff 是类型安全的(“好”),但它需要三个参数(“坏”)。第二个需要两个参数(最佳),但它不是类型安全的(“坏”),因为它依赖于字符串来指定属性。也许有一些我没有想到的使用Expression 的解决方案?

背景:用例是我希望能够“扩展”任何对象的值(在我的情况下,我有来自多个对象存储库的对象列表,这些对象可能具有包含用户 ID 作为字符串的多个属性。另一个存储库包含用户,我想将有关用户的信息添加到以前存储库中的字符串中)

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");
}

【问题讨论】:

  • 您正在寻找Expression&lt;Func&lt;T, object&gt;&gt;。您可以编译(.Compile())并调用它来获取值。
  • @john:使用Expression&lt;Func&lt;T, object&gt;&gt;DoStuff3 会是什么样子?你会写它作为答案吗?或者你有链接吗?对我来说,Expersions 仍然有点混乱......
  • here
  • @john:非常感谢!

标签: c# expression-trees func


【解决方案1】:

好吧,我不久前做过类似的事情。这是一个例子:

 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);

 }

你这样称呼它。

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

【讨论】:

  • this[key] 表达式表明在复制此代码的类中还有更多内容与答案相关?
  • 不适合你。你只需要 typeof(T).GetProperty(key).SetValue()
  • 但是如果你想要这个库,可以在nuget.org/packages/Generic.LightDataTable找到它
  • 很高兴听到 ;)