How can I assign a Func using the conditional ternary operator?
var filter = (someBooleanExpressionHere)
? new Func<Something, bool>(x => x.SomeProp < 5)
: x => x.SomeProp >= 5;
How can I assign a Func conditionally between lambdas using the conditional ternary operator?
You can convert a lambda expression to a particular target delegate type, but in order to determine the type of the conditional expression, the compiler needs to know the type of each of the second and third operands. While they're both just "lambda expression" there's no conversion from one to the other, so the compiler can't do anything useful.
I wouldn't suggest using an assignment, however - a cast is more obvious:
Func<Order, bool> predicate = id == null
? (Func<Order, bool>) (p => p.EmployeeID == null)
: p => p.EmployeeID == id;
Note that you only need to provide it for one operand, so the compiler can perform the conversion from the other lambda expression.
Assign a lambda expression using the conditional (ternary) operator
The C# compiler tries to create the lambdas independently and cannot unambiguously determine the type. Casting can inform the compiler which type to use:
Action<int> ff = (1 == 2)
? (Action<int>)((int n) => Console.WriteLine("nope {0}", n))
: (Action<int>)((int n) => Console.WriteLine("nun {0}", n));
C# Func and Conditional Operator
The 'type inference' on the conditional operator is not quite good enough, I get a message like
Type of conditional expression cannot
be determined because there is no
implicit conversion between 'lambda
expression' and 'lambda expression'
you can always just be explicit on the right-hand-side, a la
var o = true ? new Func<int,int>(x => 0) : new Func<int,int>(x => 1);
In any case it's just a minor annoyance regarding how the types of lambdas, type inference, and the conditional operator interact.
Initializing capturing lambda in ternary operator
Every lambda expression has unique type (i.e. the closure type, which is a unique unnamed non-union non-aggregate class type), even with the same signature and function body; the compiler just can't deduce the common type of ternary conditional operator for the variable declared by auto
, the two closure types are irrelevant at all.
You can use std::function
instead. e.g.
std::function<bool()> l1;
if (condition)
l1 = [](){ return true; };
else
l1 = [number](){ return number == 123; };
For l4
, note that the lambda-expression with empty capture list could be converted to the corresponding function pointer implicitly. In this case both of them could be converted to the same function pointer type (i.e. bool(*)(int)
), which then could be deduced as the common type of ternary conditional operator and the type of l4
.
null-conditional operator doesn't work with Func T inside a generic method
Unfortunately I believe you have hit a edge case of the compiler. The ?.
operator needs to return default(RetrunTypeOfRHS)
for classes and default(Nullable<RetrunTypeOfRHS>)
for structs. Because you have not constrained T
to be classes or structs it can't tell which one to promote to.
The reason Action<T>
works is because the return type of the right hand side is void
for both cases so it does not need to decide which promotion to do.
You will need to use the long form you showed or have two methods with different constraints on T
public static T TestStruct<T>(Func<T> func) where T : struct
{
return func?.Invoke() ?? default(T);
}
public static T TestClass<T>(Func<T> func) where T : class
{
return func?.Invoke(); // ?? default(T); -- This part is unnecessary, ?. already
// returns default(T) for classes.
}
passing in nullable Expression Func T, TResult ? as method parameter?
There are a few problems with your code
Expression<TDelegate>
is a class, so it's nullable already; you can simply test iforderBy == null
.Nullable<T>
has a generic constraint thatT
must be astruct
, soExpression<Func<MyObject, T>>?
won't compile.- Next you'll have the problem that because the type
T
isn't bound inside the method, butx.Id
is. In other words, you won't be able to create use the conditional operator to choose between a value ofExpression<Func<MyObject, T>>
andExpression<Func<MyObject, int>>
(assuming thatId
is anint
) while still maintaining type information to pass to theOrderBy
method.
The solution is to use something along these lines:
public IPagedList<MyObject> GetAll<T>(Expression<Func<MyObject, T>> orderBy,
int pageNumber = 1, int pageSize = 10)
{
IQueryable<MyObject> objects = dataContext.MyObjects;
objects = (orderBy != null) ? objects.OrderBy(orderBy)
: objects.OrderBy(x => x.Id);
return objects.ToPagedList<MyObject>(pageNumber, pageSize);
}
The conditional operator works in this code because regardless of what you pass to OrderBy
the return type will be the same, IQueryable<MyObject>
.
Note also that you can't simply pass in a null value for orderBy
, because T
can't be inferred. You'd have to call it like this:
var results = MyClass.GetAll<int>(null);
Ultimately, you'd probably be better off creating two overloads, one that accepts an orderBy
expression, and one that doesn't.
No implicit conversion between 'lambda expression' and 'lambda expression'?
The type of the conditional expression has to be inferred as a whole - and lambda expressions always have to be converted to a specific delegate or expression tree type.
In your latter two examples, the compiler knows what it's trying to convert the lambda expression to. In the first example, it tries to work out the type of the whole conditional expression first.
A cast in one of the branches would be enough though:
protected override Func<Stream> GetStream()
{
return someBool
? (Func<Stream>)
(() => EmbeddedResourceExtractor.GetFile("SomeFile1.ext"))
: () => EmbeddedResourceExtractor.GetFile("SomeFile2.ext");
}
Sergio's fix (now deleted, but included below) will work if you were happy to evaluate someBool
at the time the function is called:
protected override Func<Stream> GetStream()
{
return () => someBool
? EmbeddedResourceExtractor.GetFile("SomeFile1.ext")
: EmbeddedResourceExtractor.GetFile("SomeFile2.ext");
}
Depending on timing, there are all kinds of different ways of fixing the example you've actually given, e.g.
protected override Func<Stream> GetStream()
{
string name = someBool ? "SomeFile1.ext" : "SomeFile2.ext";
return () => EmbeddedResourceExtractor.GetFile(name);
}
I'm guessing your real code is more complicated though.
It's a shame in some ways that C#'s type inference can't be more powerful - but it's already pretty complicated.
Related Topics
C# Short/Long/Int Literal Format
How to Run a Test Method with Multiple Parameters in Mstest
ASP.NET Core MVC:How to Get Raw JSON Bound to a String Without a Type
How to Inject a Dbcontext Instance into an Ihostedservice
The Type or Namespace Name Does Not Exist in the Namespace 'System.Web.Mvc'
Pass Array to MVC Action via Ajax
Xml Serialize Generic List of Serializable Objects
How to Resolve Ioptions Instance Inside Configureservices
What Does Missingmanifestresourceexception Mean and How to Fix It
Memory Address of an Object in C#
Servicestack.Net Redis: Storing Related Objects VS. Related Object Ids
JSON Convert Empty String Instead of Null
How to Delete Cookies from Windows.Form
How to Check If a String Exists in Another String
Dropdownlist in MVC 4 with Razor