Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 507 Vote(s) - 3.57 Average
  • 1
  • 2
  • 3
  • 4
  • 5
An expression tree lambda may not contain a null propagating operator

#1
The line `price = co?.price ?? 0,` in the following code gives me the above error, but if I remove `?` from `co.?` it works fine.

I was trying to follow [this MSDN example][1] where they are using `?` on line `select new { person.FirstName, PetName = subpet?.Name ?? String.Empty };` So, it seems I need to understand when to use `?` with `??` and when not to.

**Error**:

>an expression tree lambda may not contain a null propagating operator

public class CustomerOrdersModelView
{
public string CustomerID { get; set; }
public int FY { get; set; }
public float? price { get; set; }
....
....
}
public async Task<IActionResult> ProductAnnualReport(string rpt)
{
var qry = from c in _context.Customers
join ord in _context.Orders
on c.CustomerID equals ord.CustomerID into co
from m in co.DefaultIfEmpty()
select new CustomerOrdersModelView
{
CustomerID = c.CustomerID,
FY = c.FY,
price = co?.price ?? 0,
....
....
};
....
....
}


[1]:

[To see links please register here]

Reply

#2
The example you were quoting from uses LINQ to Objects, where the implicit lambda expressions in the query are converted into *delegates*... whereas you're using EF or similar, with `IQueryable<T>` queryies, where the lambda expressions are converted into *expression trees*. Expression trees don't support the null conditional operator (or tuples).

Just do it the old way:

price = co == null ? 0 : (co.price ?? 0)

(I believe the null-coalescing operator is fine in an expression tree.)
Reply

#3
The code you link to uses `List<T>`. `List<T>` implements `IEnumerable<T>` but not `IQueryable<T>`. In that case, the projection is executed in memory and `?.` works.

You're using some `IQueryable<T>`, which works very differently. For `IQueryable<T>`, a representation of the projection is created, and your LINQ provider decides what to do with it at runtime. For backwards compatibility reasons, `?.` cannot be used here.

Depending on your LINQ provider, you may be able to use plain `.` and still not get any `NullReferenceException`.
Reply

#4
Jon Skeet's answer was right, in my case I was using `DateTime` for my Entity class.
When I tried to use like
```
(a.DateProperty == null ? default : a.DateProperty.Date)
```
I had the error
```
Property 'System.DateTime Date' is not defined for type 'System.Nullable`1[System.DateTime]' (Parameter 'property')
```

So I needed to change `DateTime?` for my entity class and
```
(a.DateProperty == null ? default : a.DateProperty.Value.Date)
```
Reply

#5
While expression tree does not support the C# 6.0 null propagating, what we can do is create a visitor that modify expression tree for safe null propagation, just like the operator does!

[Here is mine:]()

```c#
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);
}
}
}
```

It passes on the following tests:

```c#
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");
}
}
```
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through