9

类似:将字符串转换为 Linq.Expressions 或使用字符串作为选择器?

类似的一个:将 Linq 表达式作为字符串传递?

另一个具有相同答案的问题:如何从 C# 中的字符串创建基于动态 lambda 的 Linq 表达式?

问一个有很多类似问题的东西的原因:

这些类似问题的公认答案是不可接受的,因为它们都引用了 4 年前为旧框架 (.net 3.5) 编写的库(假定它是由代码大师 Scott Gu 编写的),除了提供链接作为答案。

有一种方法可以在不包含整个库的情况下在代码中执行此操作。

以下是针对这种情况的一些示例代码:

    public static void getDynamic<T>(int startingId) where T : class
    {
        string classType = typeof(T).ToString();
        string classTypeId = classType + "Id";
        using (var repo = new Repository<T>())
        {
            Build<T>(
             repo.getList(),
             b => b.classTypeId //doesn't compile, this is the heart of the issue
               //How can a string be used in this fashion to access a property in b?
            )
        }
    }

    public void Build<T>(
        List<T> items, 
        Func<T, int> value) where T : class
    {
        var Values = new List<Item>();
        Values = items.Select(f => new Item()
        {
            Id = value(f)
        }).ToList();
    }

    public class Item
    {
     public int Id { get; set; }
    }

请注意,这并不是要将整个字符串转换为表达式,例如

query = "x => x.id == somevalue";

而是试图只使用字符串作为访问

query = x => x.STRING;
4

3 回答 3

15

这是一个表达式树尝试。我仍然不知道这是否适用于实体框架,但我认为值得一试。

Func<T, int> MakeGetter<T>(string propertyName)
{
    ParameterExpression input = Expression.Parameter(typeof(T));

    var expr = Expression.Property(input, typeof(T).GetProperty(propertyName));

    return Expression.Lambda<Func<T, int>>(expr, input).Compile();  
}

像这样称呼它:

Build<T>(repo.getList(), MakeGetter<T>(classTypeId))

如果您可以使用 aExpression<Func<T,int>>代替 a Func,那么只需删除对 的调用Compile(并更改 的签名MakeGetter)。


编辑:在评论中,TravisJ 问他如何像这样使用它:w => "text" + w.classTypeId

有几种方法可以做到这一点,但为了便于阅读,我建议先引入一个局部变量,如下所示:

var getId = MakeGetter<T>(classTypeId);

return w => "text" + getId(w); 

要点是 getter 只是一个函数,您可以像平常一样使用它。像这样读Func<T,int>int DoSomething(T instance)

于 2012-07-13T23:50:04.207 回答
2

这是我的测试代码(linqPad)为您提供的扩展方法:

class test
{
   public string sam { get; set; }
   public string notsam {get; set; }
}

void Main()
{
   var z = new test { sam = "sam", notsam = "alex" };

   z.Dump();

   z.GetPropertyByString("notsam").Dump();

   z.SetPropertyByString("sam","john");

   z.Dump();
}

static class Nice
{
  public static void  SetPropertyByString(this object x, string p,object value) 
  {
     x.GetType().GetProperty(p).SetValue(x,value,null);
  }

  public static object GetPropertyByString(this object x,string p)
  {
     return x.GetType().GetProperty(p).GetValue(x,null);
  }
}

结果:

结果

于 2012-07-14T00:14:49.330 回答
1

我还没有尝试过,不确定它是否会起作用,但你可以使用类似的东西:

b => b.GetType().GetProperty(classTypeId).GetValue(b, null);

于 2012-07-13T23:46:45.900 回答