假设我们有两个类:
public class ParentEntity
{
public ChildEntity Child { get; set; }
}
public class ChildEntity
{
public byte? NullableValue { get; set; }
public byte Value { get; set; }
}
任务是在linq表达式中表达以下代码:
parent.Child == null ? null : parent.Child.NullableValue
为此,我尝试使用以下代码:
public static Expression GetCondition<TParent, TChild, TChildKey>(
Expression<Func<TParent, TChild>> pe,
Expression<Func<TChild, TChildKey>> ce)
{
var test = Expression.Equal(pe.Body, Expression.Constant(null));
var ifTrue = Expression.Constant(Activator.CreateInstance<TChildKey>());
var ifFalse = Expression.Property(pe.Body,
(ce.Body as MemberExpression).Member.Name);
return Expression.Condition(test, ifTrue, ifFalse);
}
使用
运行此代码Expression<Func<ParentEntity, ChildEntity>> pe = n => n.Child;
GetCondition(pe, n => n.Value); // ok
GetCondition(pe, n => n.NullableValue); // throws an ArgumentException
在最后一行(ArgumentException
的return语句处)抛出GetCondition
,表示参数类型不匹配。
分析了这段代码后,我发现当Activator.CreateInstance<TChildKey>()
为object
时,TChildKey
会返回TChildKey
,而不是System.Nullable<T>
,即ifTrue.Type
是object
,而我预计它是System.Nullable<byte>
。
SO: Creating a nullable object via Activator.CreateInstance returns null指向Reflection and Nullable
讨论了这个问题但这些都没有提出任何解决问题的方法。
有没有办法创建一个System.Nullable<T>
类型的实例,其值为null
?
或者也许有其他方式表达原始条件表达式?
答案 0 :(得分:2)
您应该尝试Expression.New
:
var ifTrue = Expression.New(typeof(Nullable<int>));
答案 1 :(得分:0)
这对你有用吗</ p>
public static Expression GetCondition<TParent, TChild, TChildKey>(
Expression<Func<TParent, TChild>> pe,
Expression<Func<TChild, TChildKey>> ce)
{
var test = Expression.Equal(pe.Body, Expression.Constant(null));
ConstantExpression ifTrue;
Type type = typeof(TChildKey);
// check if it is a nullable type
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Nullable<>))
{
ifTrue = Expression.Constant(default(TChildKey));
}
else
{
ifTrue = Expression.Constant( Activator.CreateInstance<TChildKey>());
}
var ifFalse = Expression.Property(pe.Body, (ce.Body as MemberExpression).Member.Name);
return Expression.Condition(test, ifFalse, ifFalse);
}
答案 2 :(得分:0)
另一种选择是使用两个参数函数重载明确指定Expression.Constant
创建的常量类型。
var ifTrue = Expression.Constant(Activator.CreateInstance<TChildKey>(), typeof(TChildKey));
Nullable<>
需要一些非常小心的处理,特别是在空值之外。明确是有帮助的,并且在做标准之外的任何事情时经常是必要的。