我有以下课程Person
,并使用自定义Where
方法:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Where(Expression<Func<Person, bool>> predicate)
{
return String.Empty;
}
}
如何以可枚举的方式检索Expression
参数名称和值?
Person p = new Person();
p.Where(i => i.Name == "Shlomi" && i.Age == 26);
用于根据表达式的名称和值构建带有参数的字符串查询。
// Eventually I will convert the above into the following:
string Query = "select * from person where name = @Name AND Age = @Age";
SqlParameter[] param = new SqlParameter[] {
new SqlParameter("@Name","Shlomi"),
new SqlParameter("@Age","26")
};
答案 0 :(得分:9)
我当然认为you should follow StriplingWarrior's advice并使用LINQ to Entities或LINQ to SQL,但为了重新发明轮子(不好),我将构建a prior answer of mine。
// Start with a method that takes a predicate and retrieves the property names
static IEnumerable<string> GetColumnNames<T>(Expression<Func<T,bool>> predicate)
{
// Use Expression.Body to gather the necessary details
var members = GetMemberExpressions(predicate.Body);
if (!members.Any())
{
throw new ArgumentException(
"Not reducible to a Member Access",
"predicate");
}
return members.Select(m => m.Member.Name);
}
现在,您需要遍历表达式树,访问每个候选表达式,并确定它是否包含MemberExpression
。下面的GetMemberExpressions
方法将遍历表达式树并检索其中的每个MemberExpression
:
static IEnumerable<MemberExpression> GetMemberExpressions(Expression body)
{
// A Queue preserves left to right reading order of expressions in the tree
var candidates = new Queue<Expression>(new[] { body });
while (candidates.Count > 0)
{
var expr = candidates.Dequeue();
if (expr is MemberExpression)
{
yield return ((MemberExpression)expr);
}
else if (expr is UnaryExpression)
{
candidates.Enqueue(((UnaryExpression)expr).Operand);
}
else if (expr is BinaryExpression)
{
var binary = expr as BinaryExpression;
candidates.Enqueue(binary.Left);
candidates.Enqueue(binary.Right);
}
else if (expr is MethodCallExpression)
{
var method = expr as MethodCallExpression;
foreach (var argument in method.Arguments)
{
candidates.Enqueue(argument);
}
}
else if (expr is LambdaExpression)
{
candidates.Enqueue(((LambdaExpression)expr).Body);
}
}
}
答案 1 :(得分:2)
问题是Expression实际上是一棵树。
例如,您有以下谓词:
Expression<Func<Person, bool>> expr = x => x.Name == "Shlomi" && x.Age == 26;
如果你检查expr,你会看到它的主体有“AndAlso”NodeType
并且它还有两个操作数属性 - Left
和Right
每个指向另一个{ {1}}具有“等于”Expression
的对象,后者又有两个属性NodeType
和Left
,它们指向Right
类型Expression
和{{} 1}}分别。
虽然您可以处理该树并提取所需的所有信息,但您最终将实现自己的LINQ2SQL提供程序,例如:重新发明一个轮子。如果您有这种感觉,我希望我提供足够的信息来开始挖掘...
答案 2 :(得分:1)
你想要做的事情非常复杂,并且有完整的框架可以做到这一点,所以你不必自己编写逻辑。看看LINQ to Entities和LINQ to SQL,例如