问题:以下代码中的行new_t3 = 0, 3, 3
new_t6 = 3, 2, 3
new_t9= 1, 3, 2
给出了上述错误。但如果我从price = co?.price ?? 0,
中移除?
,它就可以了。我试图关注他们在co.?
上使用?
的{{3}},因此,似乎我需要了解何时将select new { person.FirstName, PetName = subpet?.Name ?? String.Empty };
与?
一起使用不要。
错误:
表达式树lambda可能不包含空传播运算符
??
答案 0 :(得分:80)
您引用的示例使用LINQ to Objects,其中查询中的隐式lambda表达式转换为委托 ...而您正在使用EF或类似的{{1} } queryies,其中lambda表达式转换为表达式树。表达式树不支持空条件运算符(或元组)。
以旧方式做到:
wrapper.java.additional.**13**=-Dremote.host.ip="1.2.3.4"
(我相信null-coalescing运算符在表达式树中很好。)
答案 1 :(得分:6)
您链接的代码使用List<T>
。 List<T>
实施IEnumerable<T>
但不IQueryable<T>
。在这种情况下,投影在内存中执行,?.
可以正常工作。
您正在使用某些IQueryable<T>
,其效果非常不同。对于IQueryable<T>
,将创建投影的表示,并且您的LINQ提供程序决定在运行时如何处理它。出于向后兼容性原因,此处不能使用?.
。
根据您的LINQ提供商,您可以使用普通.
,但仍然无法获得任何NullReferenceException
。
答案 2 :(得分:1)
乔恩·斯基特(Jon Skeet)的回答是正确的,就我而言,我在实体类中使用的是DateTime
。
当我尝试使用like
(a.DateProperty == null ? default : a.DateProperty.Date)
我遇到了错误
Property 'System.DateTime Date' is not defined for type 'System.Nullable`1[System.DateTime]' (Parameter 'property')
所以我需要为我的实体类更改DateTime?
和
(a.DateProperty == null ? default : a.DateProperty.Value.Date)
答案 3 :(得分:0)
虽然表达式树不支持C#6.0 null传播,但是我们可以做的是创建一个访问者,该访问者可以修改表达式树以实现安全的null传播,就像运算符一样!
public class NullPropagationVisitor : ExpressionVisitor
{
private readonly bool _recursive;
public NullPropagationVisitor(bool recursive)
{
_recursive = recursive;
}
protected override Expression VisitUnary(UnaryExpression propertyAccess)
{
if (propertyAccess.Operand is MemberExpression mem)
return VisitMember(mem);
if (propertyAccess.Operand is MethodCallExpression met)
return VisitMethodCall(met);
if (propertyAccess.Operand is ConditionalExpression cond)
return Expression.Condition(
test: cond.Test,
ifTrue: MakeNullable(Visit(cond.IfTrue)),
ifFalse: MakeNullable(Visit(cond.IfFalse)));
return base.VisitUnary(propertyAccess);
}
protected override Expression VisitMember(MemberExpression propertyAccess)
{
return Common(propertyAccess.Expression, propertyAccess);
}
protected override Expression VisitMethodCall(MethodCallExpression propertyAccess)
{
if (propertyAccess.Object == null)
return base.VisitMethodCall(propertyAccess);
return Common(propertyAccess.Object, propertyAccess);
}
private BlockExpression Common(Expression instance, Expression propertyAccess)
{
var safe = _recursive ? base.Visit(instance) : instance;
var caller = Expression.Variable(safe.Type, "caller");
var assign = Expression.Assign(caller, safe);
var acess = MakeNullable(new ExpressionReplacer(instance,
IsNullableStruct(instance) ? caller : RemoveNullable(caller)).Visit(propertyAccess));
var ternary = Expression.Condition(
test: Expression.Equal(caller, Expression.Constant(null)),
ifTrue: Expression.Constant(null, acess.Type),
ifFalse: acess);
return Expression.Block(
type: acess.Type,
variables: new[]
{
caller,
},
expressions: new Expression[]
{
assign,
ternary,
});
}
private static Expression MakeNullable(Expression ex)
{
if (IsNullable(ex))
return ex;
return Expression.Convert(ex, typeof(Nullable<>).MakeGenericType(ex.Type));
}
private static bool IsNullable(Expression ex)
{
return !ex.Type.IsValueType || (Nullable.GetUnderlyingType(ex.Type) != null);
}
private static bool IsNullableStruct(Expression ex)
{
return ex.Type.IsValueType && (Nullable.GetUnderlyingType(ex.Type) != null);
}
private static Expression RemoveNullable(Expression ex)
{
if (IsNullableStruct(ex))
return Expression.Convert(ex, ex.Type.GenericTypeArguments[0]);
return ex;
}
private class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression _oldEx;
private readonly Expression _newEx;
internal ExpressionReplacer(Expression oldEx, Expression newEx)
{
_oldEx = oldEx;
_newEx = newEx;
}
public override Expression Visit(Expression node)
{
if (node == _oldEx)
return _newEx;
return base.Visit(node);
}
}
}
它通过了以下测试:
private static string Foo(string s) => s;
static void Main(string[] _)
{
var visitor = new NullPropagationVisitor(recursive: true);
Test1();
Test2();
Test3();
void Test1()
{
Expression<Func<string, char?>> f = s => s == "foo" ? 'X' : Foo(s).Length.ToString()[0];
var fBody = (Expression<Func<string, char?>>)visitor.Visit(f);
var fFunc = fBody.Compile();
Debug.Assert(fFunc(null) == null);
Debug.Assert(fFunc("bar") == '3');
Debug.Assert(fFunc("foo") == 'X');
}
void Test2()
{
Expression<Func<string, int>> y = s => s.Length;
var yBody = visitor.Visit(y.Body);
var yFunc = Expression.Lambda<Func<string, int?>>(
body: yBody,
parameters: y.Parameters)
.Compile();
Debug.Assert(yFunc(null) == null);
Debug.Assert(yFunc("bar") == 3);
}
void Test3()
{
Expression<Func<char?, string>> y = s => s.Value.ToString()[0].ToString();
var yBody = visitor.Visit(y.Body);
var yFunc = Expression.Lambda<Func<char?, string>>(
body: yBody,
parameters: y.Parameters)
.Compile();
Debug.Assert(yFunc(null) == null);
Debug.Assert(yFunc('A') == "A");
}
}