I'm trying to write a generic method that supplies parameters and calls a function, like this:
class MyClass {
public int Method(float arg) => 0;
}
TResult Call<T1, TResult>(Func<T1, TResult> func) =>
func(default(T1));
void Main()
{
var m = new MyClass();
var r1 = Call<float, int>(m.Method);
var r2 = Call(m.Method); // CS0411
}
The last line fails to compile with CS0411. Is there any workaround to get type inference to work here?
Use case: using AutoFixture to generate function call parameters.
Unfortunately no, that's a limitation of type inference in C#. It doesn't really do much with return types, which is what's needed in your case to fully infer the generic arguments to Call<>.
Related
I have a compiledLambda function that runs against an interface. Unfortunately the interface is just a marker interface and the real type is generated on the fly during runtime and has properties I want to do a grouping on.
Here's some sample code:
class Program
{
static void Main(string[] args)
{
// Just an example assignment: In the real life scenario the dynamic generated class is created during runtime.
IEnumerable<IDynamicGeneratedModelClass> list = GetDataFromService();
// get the 'real' type from the list
LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(list.First().GetType(), typeof(object), "SomeProperty");
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpression.Compile();
// Expected result: Group list on "SomeProp"
var result = list.GroupBy(compiledLambdaFunction);
}
private static IList<IDynamicGeneratedModelClass> GetDataFromService()
{
return new List<IDynamicGeneratedModelClass> {
new DynamicGeneratedModelClass("Class1"),
new DynamicGeneratedModelClass("Class2")
};
}
}
public interface IDynamicGeneratedModelClass
{}
public class DynamicGeneratedModelClass : IDynamicGeneratedModelClass
{
public DynamicGeneratedModelClass(string someProperty)
{
SomeProperty = someProperty;
}
public string SomeProperty { get; }
}
When the the lambda expression is compiled it throws the following exception:
System.InvalidCastException: 'Unable to cast object of type
'System.Func`2[ConsoleApp12.DynamicGeneratedModelClass,System.Object]'
to type
'System.Func`2[ConsoleApp12.IDynamicGeneratedModelClass,System.Object]'.'
Could you please give me a hint what I am doing wrong and how to fix it ?
The first generic parameter of the Func<T, TResult> delegate is declared as contravariant (in), which means that you can assign delegate with less derived parameter to delegate with more derived parameter, but not vice versa (in another words, you can cast Func<IDynamicGeneratedModelClass,Object> to Func<DynamicGeneratedModelClass,Object>, but cannot cast Func<DynamicGeneratedModelClass,Object> to Func<IDynamicGeneratedModelClass,Object>).
To avoid this problem, instead of lambda expression you generate now:
// lambda has "wrong" type Func<DynamicGeneratedModelClass, object>
(DynamicGeneratedModelClass item) => item.SomeProperty
generate lambda equivalent to this:
// lambda now has "correct" type Func<IDynamicGeneratedModelClass, object>
(IDynamicGeneratedModelClass item) => ((DynamicGeneratedModelClass)item).SomeProperty
I'm not familiar with the DynamicExpression library you used to generate you lambda, but this can be easily done using just System.Linq.Expression classes:
var itemType = list.First().GetType();
var propertyName = "SomeProperty";
var parameterExpr = Expression.Parameter(typeof(IDynamicGeneratedModelClass));
var castExpr = Expression.Convert(parameterExpr, itemType);
var propExpr = Expression.Property(castExpr, propertyName);
var lambdaExpr = Expression.Lambda(propExpr, parameterExpr);
// Compiled lambda is now of type Func<IDynamicGeneratedModelClass, object>
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpr.Compile();
var result = list.GroupBy(compiledLambdaFunction);
I have read about Func<>, which says it iss a delegate and you can use it like for example:
Func<class,bool>
means you send a class or anything and get a bool result, this is what I got!
but what does the following mean?
Func<Class, bool> predicate
I have no idea, can you make it clear for me?
The former will not compile since class is a registered keyword and can only be used for class definitions.
The latter is a Func<T, TResult> which is a function that takes a parameter of type T and returns an object of type TResult. So in your case, the function takes an object of type Class and returns a bool.
The naming of Class is unfortunate but it’s actually allowed to use that identifier for a type. The following would be an example that takes such an object of type Class and then checks a property of it, returning true or false depending on the success of the comparison.
Func<Class,bool> predicate = obj => obj.Prop == "Foo";
var x = new Class();
x.Prop = "Foo";
Console.WriteLine(predicate(x)); // true
// with the following class definition
public class Class
{
public string Prop { get; set; }
}
A Func<> object is callable, just like methods, so we can use parentheses to call it and pass the object here. This would be equivalent to a method like this:
public bool predicate(Class obj)
{
return obj.Prop == "Foo";
}
But the usual way to use Func<> is using lambda expressions to be able to create functions quickly inline. This is very commonly used in LINQ where you use lambda expressions, and as such Func<> objects, all the time:
var filtered = listOfOjects.Where(obj => obj.Prop == "Foo").ToList();
// ^^^^^^^^^^^^^^^^^^^^^^^^
// this is the predicate function from above
// so you could also pass the predicate Func from above:
var filtered = listOfObjects.Where(predicate).ToList()
Func<MyClass,bool> is a delegate type
In Func<MyClass, bool> predicate , predicate is a delegate variable.
You would normally see something like
Func<MyClass, bool> predicate = c => c.IsValid;
...
if (predicate(myClass1)) DoSomething();
That's just how you instantiate the Func. Compare to a string:
string str;
If you want to instantiate and assign it at the same time, you do something like this:
Func<string, bool> isLongerThanThree = input => input.Length > 3;
isLongerThanThree("string"); // Returns "true"
Are you referring to the word predicate?
That's just the name of a parameter. Notice the similarity:
MyMethod(int myAge)
MyMethod(List<bool> myBooleans)
MyMethod(Func<Class,bool> myPredicate)
Also notice the similarities between:
int myAge = 30;
myAge is a variable of type int who has been given the value of 30.
Func<Class,bool> myPredicate = (x => x.IsAlive);
myPredicate is a variable of type Func<Class,bool> who has been given the value of (x => x.IsAlive).
Func<> is a delegate which represents a method which return a result. C# provides signatures for up to 15 input arguments, which should be enough to represent all possible methods you will ever need :)
it is hardly event to imagine method which has 15 input arguments. Beside Func<> there are also some special version of the delegate like Predicate<T> which is nothing else that Func<in T, bool TResult> or Action<> which represent a function without return value, return value is void.
Delegates(C# Programming Guide)
You can assign any method, static or instance or even anonymous with the matching signature to the Func<>. For example:
Func<MyClass, bool> predicate = (myClass) => {return true;} //anonymoys method
public class MyClass
{
public bool MyPredicate(MyClass myClass)
{
return true;
}
public static bool MyStaticPredicate(MyClass myClass)
{
return true;
}
}
Func<MyClass, bool> predicate = new MyClass().MyPredicate;
Func<MyClass, bool> staticPredicate = MyClass.MyStaticPredicate;
I'm implementing a fluent argument assertion library where the focus is in strong type checking on compile time. Intellisense should only show methods and extensions available for the asserted type.
I'm having problems resolving proper type arguments when creating an extension for IEnumerable.
Idea in the library is that you can call ThrowIf (or ThrowIfNot) on any type which will return you an assertion instance of type IAssertion:
public static IAssertion<T> ThrowIf<T>(this T t)
{
return new IfAssertion<T>(t);
}
Now I want to check against IEnumerable if it contains a specific item. There will be two overloads where one takes the object of type T as a parameter and the other takes a function where to do the evaluation:
public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, T2 item)
where T1 : IEnumerable<T2>
{
// assertion logic
return assertion.Value;
}
public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, Func<T2, bool> func)
where T1 : IEnumerable<T2>
{
// assertion logic
return assertion.Value;
}
Everything goes fine when using the overload taking an instance of the actual type. But the latter one with the function compiler cannot infer the type arguments properly unless cast is made:
var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // does not compile
Is there any way I could make the compiler happy without doing the cast for the function parameter?
More implementation details can be found from here:
https://bitbucket.org/mikalkai/argument-assertions/overview
Disclaimer: This answer is only valid if IAssertion can be made covariant.
Assuming that IAssertion is covariant, you don't necessarily need two generic type parameters T1 and T2 for the Contains methods. Instead, you specify IEnumerable in your interface directly and use only one generic type parameter like this:
public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, T item)
{
// assertion logic
return assertion.Value;
}
public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, Func<T, bool> func)
{
// assertion logic
return assertion.Value;
}
Then you can use the contains method like this:
var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // compiles now too
I have a method which i want to convert to Extension Method
public static string GetMemberName<T>(Expression<Func<T>> item)
{
return ((MemberExpression)item.Body).Member.Name;
}
and calling it like
string str = myclass.GetMemberName(() => new Foo().Bar);
so it evaluates to str = "Bar"; // It gives the Member name and not its value
Now when i try to convert this to extension method by this
public static string GetMemberName<T>(this Expression<Func<T>> item)
{
return ((MemberExpression)item.Body).Member.Name;
}
and call it like
string str = (() => new Foo().Bar).GetMemberName();
Error says Operator '.' cannot be applied to operand of type 'lambda expression'
Where am I wrong?
There are really two things here, first, passing () => new Foo().Bar into the method that accepts Expression<Func<T>> treats the specified expression tree as a Expression<Func<T>>, but () => new Foo().Bar is not an Expression<Func<T>> on its own.
Second, in order to get your extension method to accept any lambda (such as you're supplying), you'd have to use the type that corresponds to any expression tree. But, as you may have already guessed based on the message ... to operand of type 'lambda expression' where you'd usually see the name of the type inside the quotes, that lambda expressions are treated specially by the language, making what you're trying to do, without casting first, impossible.
The way to invoke your extension method in extension method form would be (in the case that Bar is of type string)
((Expression<Func<string>>)(() => new Foo().Bar)).GetMemberName()`
which doesn't seem like it would be all that desirable.
Where am I wrong?
The compiler is telling you exactly what's wrong - you can't use . on a lambda expression.
The lambda expression doesn't have any particular type - it's just convertible to the expression tree.
A member-access expression (which is what you're trying to do) is only available in the forms
primary-expression . identifier type-argument-list(opt)
predefined-type . identifier type-argument-list(opt)
qualified-alias-member . identifier type-argument-list(opt)
... and a lambda expression isn't a primary expression.
Interestingly, this argument doesn't hold for an anonymous method expression, but for you still can't use a member access expression on that, either. Section 7.6.4 of the C# spec lists how a member access expression is bound, and the bulk of the options are either under "If E is a predefined-type or a primary-expression classified as a type" (which doesn't apply to anonymous methods) or "If E is a property access, variable, or value, the type of which is T" - but an anonymous method is an anonymous function, and as per section 7.15: "An anonymous function does not have a value or type in and of itself".
EDIT: You can still use extension methods on expression trees, you just can't use them directly on lambda expressions. So this will work:
Expression<Func<int>> expr = () => new Foo().Bar;
string name = expr.GetMemberName();
... but it's obviously not as useful. (Ditto with a cast as per mlorbetske's answer.)
To get typed expression, you will have to write it out. As others have said, there is no way compiler will automatically infer it from a lambda expression since a lambda expression can mean two things - either a delegate or an expression tree.
You can get the expression relatively simpler, by letting the compiler infer the type for you partially, like (from this answer):
public sealed class Lambda
{
public static Func<T> Func<T>(Func<T> func)
{
return func;
}
public static Expression<Func<T>> Expression<T>(Expression<Func<T>> expression)
{
return expression;
}
}
public sealed class Lambda<S>
{
public static Func<S, T> Func<T>(Func<S, T> func)
{
return func;
}
public static Expression<Func<S, T>> Expression<T>(Expression<Func<S, T>> expression)
{
return expression;
}
}
//etc, to cover more cases
Call it like:
var expr1 = Lambda.Expression(() => new Foo().Bar);
var expr2 = Lambda<string>.Expression(x => x.Length); //etc
Your options are:
Cast backward, to exact expression type and then call extension method on it
var name = ((Expression<Func<BarType>>)(() => new Foo().Bar)).GetMemberName();
looks ugly - cure worse than cause.
Get the expression first into a variable
Expression<Func<BarType>> expr = () => new Foo().Bar;
var name = expr.GetMemberName();
Slightly better, but still looks little off for a trivial thing.
Using the Lambda classes written above
var name = Lambda.Expression(() => new Foo().Bar).GetMemberName();
Even better. It's just a little less typing.
Your first pattern, which I think is the best you can get as far as readability goes
I dont think you can improve upon that considering C# rules related to lambda expressions. That said I think few improvements can be made.
First, extend the functionality to other lambda expression types. You would need more than Func<T> types to handle all cases. Decide what are the expression types you have to handle. For instance if you have a Func<S, T> type (as in your question - Bar on Foo), it looks better. Compare this
myclass.GetMemberName(() => new Foo().Bar);
with
myclass.GetMemberName<Foo>(x => x.Bar);
I would say these overloads would do:
//for static methods which return void
public static string GetMemberName(Expression<Action> expr);
//for static methods which return non-void and properties and fields
public static string GetMemberName<T>(Expression<Func<T>> expr);
//for instance methods which return void
public static string GetMemberName<T>(Expression<Action<T>> expr);
//for instance methods which return non-void and properties and fields
public static string GetMemberName<S, T>(Expression<Func<S, T>> expr);
Now these can be used not just in the cases mentioned in comments, surely there are overlapping scenarios. For instance, if you already have instance of Foo, then its easier to call the second overload (Func<T>) overload for name of property Bar, like myclass.GetMemberName(() => foo.Bar).
Secondly, implement a GetMemberName functionality common to all these overloads. An extension method on Expression<T> or LambdaExpression would do. I prefer the latter so that you get to call it even in non-strongly typed scenarios. I would write it like this, from this answer:
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null;
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};
return nameSelector(memberSelector.Body);
}
Lastly, GetMemberName is not a good name if you're to call it non-extension way. expression.GetMemberName() sounds more logical. Member.NameFrom<int>(x => x.ToString()) or MemberName.From<string>(x => x.Length) etc are more descriptive names for static calls.
So overall the class might look like:
public static class Member
{
public static string NameFrom(Expression<Action> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Action<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T, object>> expr)
{
return expr.GetMemberName();
}
}
And usage:
var name1 = Member.NameFrom(() => Console.WriteLine());
var name2 = Member.NameFrom(() => Environment.ExitCode);
var name3 = Member.NameFrom<Control>(x => x.Invoke(null));
var name4 = Member.NameFrom<string>(x => x.Length);
Most concise and clean.
For properties and fields, it can be transformed to an anonymous class and then using reflection the member name can be read, as shown here.
public static string GetMemberName<T>(T item) where T : class
{
if (item == null)
return null;
return typeof(T).GetProperties()[0].Name;
}
Call it like
var name = GetMemberName(new { new Foo().Bar });
It's faster, but has certain quirks, like not very refactor friendly, and doesnt help in case of methods as members. See the thread..
Of all I prefer 4.
class Program
{
static delegate R Foo<I, R>(I i);
static void Main(string[] args)
{
Foo<int, string> foo = (int x) => x.ToString();
// Why can't the compiler IMPLICITLY infer the following declaration?
//Foo foo = (int x) => x.ToString();
}
}
EDIT 1: The code above is not compilable actually. The delegate I defined has static modifier that is not applicable!
This isn't about type inference, it's because there's no such type as Foo. (Foo<I,R> and Foo, if it existed, are two completely different types as far as the compiler is concerned.)
For the same reason you can't legally do any of the following:
Dictionary d = new Dictionary<int, string>();
List l = new List<string>();
Func f = new Func<int, string>(i => i.ToString());
Because Foo is not a type that has been defined, but Foo<,> is a type that has been defined.
*Removed var suggestion as it doesn't work...
C# spec states that lambdas are untyped constructs (like method groups). They can be converted to compatible types. For this reason, you can't write var something = (SomeType a) => a;
The rationale is they can be interpreted as expression trees and delegates depending on the context. There's no way to know which one is your intent outside a specific context. You cannot use a lambda expression or method group outside a context in which they can be converted to something.
C# Language Specification v4.0 (§1.4.12)
Anonymous function conversions and method group conversions
Anonymous functions and method groups do not have types in and of themselves, but may be implicitly converted to delegate types or expression tree types. Anonymous function conversions are described in more detail in §1.44 and method group conversions in §1.45.
Because there is no such type Foo. If declaring a variable of a certain type, you have to define its generic parameters as well.
In example, this works fine:
F((int x) => x.ToString());
private static void F<I,R>(Foo<I, R> foo)
{
}
You could make a small wrapper class.
static class Foo {
public static Foo<I, R> Create<I, R>(Foo<I, R> foo) {
return foo;
}
}
Then this works fine:
var foo = Foo.Create((int x) => x.ToString());