Passing a generic function as a parameter - c#

I know that what I'm doing can be done in a different way, but I'm curious about how things work. The following is a simplified code which doesn't compile, but it supposed to show my goal.
private void Execute()
{
GeneralizedFunction("1", "2", i => Transform(i));
}
void GeneralizedFunction(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction(aStringA);
B result2 = aAction(aStringB);
// Do something with A and B here
}
T Transform<T>(string aString)
{
return default(T);
}
Transform is a generic convertion from string to some object (think deserialization).
GeneralizedFunction uses two specializations of transform: one for type A and one for type B. I know I can do this in a number of other ways (say by introducing a parameter for the type of the object), but I'm looking for explanations of whether it is possible or impossible to do this with generics/lambdas. If Transform is specialized before it is passed as a parameter to GeneralizedFunction, then it's impossible. Then the question is why this possibility is restricted.

This answer doesn't explain the reason why, just how to work around the limitation.
Instead of passing an actual function, you can pass an object that has such a function:
interface IGenericFunc
{
TResult Call<TArg,TResult>(TArg arg);
}
// ... in some class:
void Test(IGenericFunc genericFunc)
{
// for example's sake only:
int x = genericFunc.Call<String, int>("string");
object y = genericFunc.Call<double, object>(2.3);
}
For your specific use case, it can be simplified to:
interface IDeserializerFunc
{
T Call<T>(string arg);
}
// ... in some class:
void Test(IDeserializerFunc deserializer)
{
int x = deserializer.Call<int>("3");
double y = deserializer.Call<double>("3.2");
}

What you're asking to do isn't possible using generics alone. The compiler needs to generate two typed versions of your Transform function: one to return type A and one for type B. The compiler has no way of knowing to generate this at compile time; only by running the code would it know that A and B are required.
One way to solve it would be to pass in the two versions:
private void Execute()
{
GeneralizedFunction("1", "2", i => Transform<A>(i), i => Transform<B>(i));
}
void GeneralizedFunction(string aStringA, string aStringB, Func<string, A> aAction, Func<string, B> bAction)
{
A result1 = aAction(aStringA);
B result2 = bAction(aStringB);
}
The compiler knows exactly what it needs to generate in this case.

Try the following signature:
void GeneralizedFunction<T>(string aStringA, string aStringB, Func<string, T> aAction)
(Note that GeneralizedFunction has to be generic; the compiler will automatically guess the type parameter when calling the method).

It seems the answer is "no".
When you call Transform directly, you have to specify a type parameter:
int i = Transform<int>("");
So hypothetically, if you could pass an incompletely-constructed generic function like you want to, you'd need to specify the type parameters as well:
void GeneralizedFunction(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction<A>(aStringA);
B result2 = aAction<B>(aStringB);
// Do something with A and B here
}
So it seems to me that you could hypothetically do this, if C# had a syntax like that.
But what's the use case? Aside from transforming strings to the default value of an arbitrary type, I don't see much use for this. How could you define a function that would provide a meaningful result in either of two different types using the same series of statements?
EDIT
An analysis of why it's not possible:
When you use a lambda expression in your code, it is compiled into either a delegate or an expression tree; in this case, it's a delegate. You can't have an instance of an "open" generic type; in other words, to create an object from a generic type, all type parameters must be specified. In other words, there's no way to have an instance of a delegate without providing arguments for all of its type parameters.
One of the C# compiler's helpful features is implicit method group conversions, where the name of a method (a "method group") can be implicitly converted to a delegate type representing one of the overloads of that method. Similarly, the compiler implicitly converts a lambda expression to a delegate type. In both cases, the compiler emits code to create an instance of the delegate type (in this case, to pass it to the function). But the instance of that delegate type still needs to have a type argument for each of its type parameters.
To pass the generic function as a generic function, it seems, the compiler would need to be able to pass the method group or the lambda expression to the method without conversion, so the aAction parameter would somehow have a type of "method group" or "lambda expression." Then, the implicit conversion to a delegate type could happen at the call sites A result1 = aAction<A>(aStringA); and B result2 = aAction<B>(aStringB);. Of course, at this point, we are well into the universe of contrafactuals and hypotheticals.
The solution I came up with over lunch was this, assuming a function Deserialize<T> that takes a string containing serialized data and returns an object of type T:
void GeneralizedFunction<T>(string aStringA, string aStringB, Func<T, string> stringGetter)
{
A result1 = Deserialize<A>(stringGetter(aStringA));
B result2 = Deserialize<B>(stringGetter(aStringB));
}
void Example(string serializedA, string serializedB, string pathToA, string pathToB, FileInfo a, FileInfo b)
{
GeneralizedFunction(serializedA, serializedB, s => s);
GeneralizedFunction(pathToA, pathToB, File.ReadAllText);
GeneralizedFunction(a, b, fi => File.ReadAllText(fi.FullName));
}

void GeneralizedFunction<T>(string aStringA, string aStringB, Func<string, T> aAction)
{
A result1 = aAction(aStringA);
B result2 = aAction(aStringB);
}
T Transform<T>(string aString)
{
return default(T);
}

Related

Why is compilation OK, when I use Invoke method, and not OK when I return Func<int,int> directly?

I don't understand this case:
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
Why is compilation OK when I use Invoke method and not OK when I return csharp Func<int,int> directly?
There are two things you need to know to understand this behaviour.
All delegates derive from System.Delegate, but different delegates have different types and therefore cannot be assigned to each other.
The C# language provides special handling for assigning a method or lambda to a delegate.
Because different delegates have different types, that means you can't assign a delegate of one type to another.
For example, given:
delegate void test1(int i);
delegate void test2(int i);
Then:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
The first line above compiles OK because it is using the special handling for assigning a lambda or a method to a delegate.
In fact, this line is effectively rewritten like this by the compiler:
test1 a = new test1(Console.WriteLine);
The second line above does not compile because it is trying to assign an instance of one type to another incompatible type.
As far at the types go, there is no compatible assignment between test1 and test2 because they are different types.
If it helps to think about it, consider this class hierarchy:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
The following code will NOT compile, even though Test1 and Test2 derive from the same base class:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
This explains why you can't assign one delegate type to another. That's just the normal C# language.
However, the crucial thing is to understand why you're allowed to assign a method or lambda to a compatible delegate. As noted above, this is part of the C# language support for delegates.
So finally to answer your question:
When you use Invoke() you are assigning a METHOD call to the delegate using the special C# language handling for assigning methods or lambdas to a delegate rather than trying to assign an incompatible type - hence it compiles OK.
To be completely clear, the code which compiles in your OP:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Is actually converted conceptually to something like:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
Whereas the failing code is attempting to assign between two incompatible types:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}
In the second case, f is of type Func<int, int>, but the method is said to return a test. These are unrelated (delegate) types, that are unconvertible to each other, so a compiler error occurs. You can go to this section of the language spec, and search for "delegate". You will find no mention of conversions between delegates that have the same signatures.
In the first case however, f.Invoke is a method group expression, which doesn't actually have a type. The C# compiler will convert method group expressions to specific delegate types according to the context, through a method group conversion.
(Quoting the 5th bullet here, emphasis mine)
An expression is classified as one of the following:
...
A method group, which is a set of overloaded methods resulting from a member lookup. [...] A method group is permitted in an invocation_expression, a delegate_creation_expression and as the left hand side of an is operator, and can be implicitly converted to a compatible delegate type.
In this case, it is converted to the test delegate type.
In other words, return f doesn't work because f already has a type, but f.Invoke doesn't have a type yet.
Issue out here is Type compatibility:
Following is the definition of Func delegate from MSDN Sources:
public delegate TResult Func<in T, out TResult>(T arg);
If you see there's no direct relation between the Func mentioned above and your defined Delegate:
public delegate int test(int i);
Why 1st snippet compiles:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
Delegates are compared using signature, which is input parameters and Output result, ultimately a Delegate is a Function pointer and two functions can be compared only via signature. At runtime the method invoked via Func is assigned to the Test delegate, since Signature is same it works seamlessly. It's a function pointer assignment, where Test delegate will now invoke the method pointed by the Func delegate
Why 2nd Snippet fails to compile
Between Func and test delegate, there's no type / assignment compatibility, Func cannot fill in as part of the Type system rules. Even when its result can be assigned and filled in test delegate as done in the first case.

Func<T, TResult> parameter - The type arguments for method cannot be inferred from the usage

I have the following method
Func<string,IEnumerable<dynamic>> getLpVideos = delegate(string language)
{
var id = GetBy(language);
return new List();
};
I want to pass a parameter like that to a generic method, but I am confused with how to use this parameter at GetObjectFromMemoryCacheWithDefParams and how to call GetObjectFromMemoryCacheWithDefParams:
public T GetObjectFromMemoryCacheWithDefParams<T>(
string key, Func<string, T> defGetValueFunc) where T : class
{
var result = _cache.Get(key) as T;
return result ?? defGetValueFunc();//here error
}
//The type arguments for method cannot be inferred from the usage
var result = CacheService
.GetObjectFromMemoryCacheWithDefParams(casheName, getLpVideos(lng));
Only when the type parameter is explicitly provided does it work.
You are not passing in a Func<string, T> as expected. You're passing an IEnumerable<dynamic> instead, which is a dynamic expression evaluated at runtime. Note that getLpVideos(lng) is not a function, it is a function invocation, which means its return value is used as the second parameter, not the function itself. You need this instead:
var result = CacheService
.GetObjectFromMemoryCacheWithDefParams(casheName, getLpVideos);
Additionally, you need to fix your function invocation within the GetObjectFromMemoryCacheWithDefParams method -- it expects an input parameter, which you don't supply:
So change this:
return result ?? defGetValueFunc();
to this:
return result ?? defGetValueFunc(key);
If I understand your problem correctly, you just want to get the call to work. In that case
you just need to tell it explicitly what type T is. In your case that is IEnumerable<dynamic>. So you can just call
var result = CacheService.
GetObjectFromMemoryCacheWithDefParams<IEnumerable<dynamic>>(
casheName,
getLpVideos(lng)
);
You need to pass a string into defGetValueFunc and specify the type of T explicitly
public T GetObjectFromMemoryCacheWithDefParams<T>(string key, Func<string,T> defGetValueFunc) where T : class
{
var result = _cache.Get(key) as T;
return result ?? defGetValueFunc(*somestring*);
}
var result = CacheService.GetObjectFromMemoryCacheWithDefParams<IEnumerable<dynamic>>(casheName, getLpVideos(lng) );
Are you sure that's exactly the code you're trying to compile? And does the error actually happen exactly where you say it does?
If so, then it appears to me that the problem with your code is that you are simply not invoking the delegate parameter correctly. You are passing a delegate instance that requires a single string parameter to be passed to it. But in your code, you are not passing any parameter:
public T GetObjectFromMemoryCacheWithDefParams<T>(
string key, Func<string, T> defGetValueFunc) where T : class
{
var result = _cache.Get(key) as T;
return result ?? defGetValueFunc(--> you need a parameter here! <--);//here error
}
I don't know what parameter you should be passing, as the anonymous method you've included in your post doesn't even use the parameter (except to retrieve a value that is ignored). But you have to pass something.
I don't think there's actually anything wrong with type inference here. This simple example, which is essentially identical to yours (except that I invoke the delegate correctly) compiles just fine:
static T Method<T>(string s, Func<string, T> f) where T : class
{
return f(s);
}
static void OtherMethod()
{
Func<string, IEnumerable<dynamic>> f = l => new List<object>();
Method("foo", f);
}
So clearly the compiler can infer the correct type, given correct code. :)

How to define parameter names for higher order functions in C#

In C# it is possible to create higher order functions, ie. functions g taking functions as arguments. Say I want to create such a function which given a function f and returns another function extending its functionality. How do I define argument names for the returned enhanced method? The motivation being, that I'm working with higher order methods in general, some of which produce new methods.. and these can be difficult to use as there is no parameter names etc. attached to them.
An example illustrating how g and f respectively could be defined in C#:
I define a method Extend that can extens methods taking a T as argument and returning an S.
static class M
{
public static Func< T, S> Extend(Func< T, S> functionToWrap)
{
return (someT) =>
{
...
var result = functionToWrap(someT);
...
return result;
};
}
}
We can then extend a method on our class without changing the method.
class Calc2
{
public Func< int, int> Calc;
public Calc2()
{
Calc = M.Extend< int, int>(CalcPriv);
}
private int CalcPriv(int positiveNumber)
{
if(positiveNumber < 0) throw new Exception(...);
Console.WriteLine("calc " + i);
return i++;
}
}
Alas, the argument name positiveNumber is no longer available, since the only available information is Func<int, int> Calc. That is when I use the extended method by typing new Calc2().Calc(-1) I get no help from the IDE that in fact my argument is wrong.
It would be nice if we could define a delegate and cast it to this, however, this is not possible.
Any suggestions?
If you only want a fixed delegate type with named parameters then you can just define your own delegate type:
Func is just defined like this:
public delegate TResult Func<in T, out TResult>(T arg)
So you can define your own delegate type with the parametername you want.
But in your example you want to preserve the delegate type passed in, so this doesn't work here. In theory you could define your function like this:
public static T Extend(T functionToWrap)
{
}
Unfortunately there are no good generic constraints which restrict the input type to a delegate with the right signature(Or even just delegates at all). But without these constraints the implementation would become so ugly, and you'd lose so much static type safety that IMO it's not worth it.
One workaround is using:
new MyFunc(Extend(f))
where MyFunc defines the parameternames you want.
Or you could do the following:
public static T ConvertDelegate<T>(Delegate d)
{
if (!(typeof(T).IsSubclassOf(typeof(Delegate))))
throw new ArgumentException("T is no Delegate");
if (d == null)
throw new ArgumentNullException();
MulticastDelegate md = d as MulticastDelegate;
Delegate[] invList = null;
int invCount = 1;
if (md != null)
invList = md.GetInvocationList();
if (invList != null)
invCount = invList.Length;
if (invCount == 1)
{
return (T)(object)Delegate.CreateDelegate(typeof(T), d.Target, d.Method);
}
else
{
for (int i = 0; i < invList.Length; i++)
{
invList[i] = (Delegate)(object)ConvertDelegate<T>(invList[i]);
}
return (T)(object)MulticastDelegate.Combine(invList);
}
}
public static TDelegate Extend<TDelegate,TArg,TResult>(Func<TArg,TResult> functionToWrap)
where TDelegate:class
{
Func<TArg,TResult> wrappedFunc= DoTheWrapping(functionToWrap);
return ConvertDelegate<TDelegate>(wrappedFunc);
}
BTW the ConvertDelegate function can be used to get Co/Contravariance on Delegates even prior to .net 4.
It is possible to cast to a delegate with named parameters, by dynamically binding a newly constructed delegate to the underlying Func delegate method:
public delegate double CalcFunc(double value);
static class M
{
public static Func<T, S> Extend<T,S>(Func<T, S> functionToWrap)
{
return (someT) => functionToWrap(someT);
}
}
class Program
{
private static double Calc(double input)
{
return 2*input;
}
[STAThread]
static void Main()
{
Func<double, double> extended = M.Extend<double, double>(Calc);
CalcFunc casted = (CalcFunc)Delegate.CreateDelegate(typeof(CalcFunc), extended.Target, extended.Method);
Console.WriteLine(casted(2) + " == 4");
Console.WriteLine("I didn't crash!");
Console.ReadKey();
}
}
One word of warning: this will not do any compile-time checking of the cast. If the signatures don't match exactly, you'll get a bind failure at runtime (excepting special support for contravariance in .NET 4).
That's the beauty of anonymous delegates; they're anonymous. A Func is a delegate to a method that takes an int and returns an int. What the function actually does, and therefore the names of the parameters, is irrelevant.
The only way this would work is if Calc were of a named delegate type, defined with a signature identical to CalcPriv. It would all still work as written, including the anonymous extension, but you'd have a named parameter for Calc.
Another way to impart the information would be to xml-doc Calc with a ///<summary></summary> tag describing the parameter Calc was designed to take.
Lastly, you could derive from Func<T,TResult> to create a TakesPositiveInteger<T,TResult> class. This is going a little far, but if you wanna talk about self-documenting code...

Passing Delegate object to method with Func<> parameter

I have a method Foo4 that accepts a parameter of the type Func<>. If I pass a parameter of anonymous type , I get no error. But if I create and pass an object of the type 'delegate' that references to a Method with correct signature, I get compiler error. I am not able to understand why I am getting error in this case.
class Learn6
{
delegate string Mydelegate(int a);
public void Start()
{
Mydelegate objMydelegate = new Mydelegate(Foo1);
//No Error
Foo4(delegate(int s) { return s.ToString(); });
//This line gives compiler error.
Foo4(objMydelegate);
}
public string Foo1(int a) { return a.ToString();}
public void Foo4(Func<int, string> F) { Console.WriteLine(F(42)); }
}
It works if you pass a reference to the method directly:
Foo4(Foo1);
This is because actual delegates with the same shape are not inherently considered compatible. If the contracts are implicit, the compiler infers the contract and matches them up. If they are explicit (e.g. declared types) no inference is performed - they are simply different types.
It is similar to:
public class Foo
{
public string Property {get;set;}
}
public class Bar
{
public string Property {get;set;}
}
We can see the two classes have the same signature and are "compatible", but the compiler sees them as two different types, and nothing more.
Because Func<int, string> and MyDelegate are different declared types. They happen to be compatible with the same set of methods; but there is no implicit conversion between them.
//This line gives compiler error.
Foo4(objMydelegate);
//This works ok.
Foo4(objMydelegate.Invoke);
depends on the scenario, but in the general case there's no reason to keep around the Mydelegate type, just use Func<int, string> everywhere :)

Delegates with return value type inference (C#)

I'm still new to delegates and I've been playing with the Delegate-based Data Access Layer described in Steven John Metsker's "Design Patterns in C#" book (an excellent read!). It defines the data access delegate like this:
public delegate object BorrowReader(IDataReader reader);
The result of using this is code that looks like one of these:
var result = Foo.Bar(new BorrowReader(DoFooBarMagic));
var result = Foo.Bar(DoFooBarMagic);
However, since the delegate's return type is "object", you need to cast to get whatever the method ("DoFooBarMagic" in this example) really returns. So if "DoFooBarMagic" returns List, you'd need to do something like this:
var result = Foo.Bar(DoFooBarMagic) as List<string>;
What I'd like is to be able to skip the cast and have the return type of the delegate inferred from the return type of the delegate method. My thought was maybe there's a way to use a Type parameter to inference the return type. Something like one of these:
public delegate T BorrowReader<T>(IDataReader reader);
List<string> result = Foo.Bar(new BorrowReader(DoFooBarMagic));
//Look, Ma, no cast!
var result2 = Foo.Bar(DoFooBarMagic);
Where the type of the return is inferred from the return type of the delegate method, but that appears not to work. Instead you have to do this:
public delegate T BorrowReader<T>(IDataReader reader);
var result = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
Which hardly seems better than the cast.
So is there a way to infer the return type of the delegate from the return type of the delegate method?
Edit to Add:
I can change the signature of Foo.Bar if need be. The current signature is essentially this:
public static T Bar<T>(string sprocName,
DbParameter[] params,
BorrowReader<T> borrower);
Note: that signature is the result of the current state, which is using this delegate definition:
public delegate T BorrowReader<T>(IDataReader reader);
How about:
public static T Bar2<T>(Func<IDataReader,T> func) where T : class
{
BorrowReader borrower = new BorrowReader(func);
return (T) Foo.Bar(borrower);
}
I know it's still doing the cast anyway, which is ugly, but it should work. (I originally thought you could get away with an implicit conversion from func, but apparently not. At least not before C# 4.0.)
Of course, if you can change the signature of Foo.Bar to be generic, you're laughing...
EDIT: To answer the comment: if the signature of the method is changed to take a generic delegate, e.g.
public static T Bar<T>(Func<IDataReader, T> func)
then the calling code can nearly just be:
var result = Foo.Bar(DoFooBarMagic);
Unfortunately, type inference doesn't work with method groups so you have to use either:
Func<IDataReader, List<string>> func = DoFooBarMagic;
var result = Foo.Bar(func);
or (nicer, if slightly less efficient)
var result = Foo.Bar(reader => DoFooBarMagic(reader));
So you're right - this answer didn't quite get the OP to exactly what was required, but presumably it came close enough to get acceptance. Hopefully this edit is helpful to explain the rest :)
It's ugly, but you can use an out parameter. From my enum parser:
public static T Parse<T>(string value)
{
// return a value of type T
}
public static void Parse<T>(string value, out T eValue)
{
// do something and set the out parameter
}
// now can be called via either
SomeEnum blah = Enums.Parse<SomeEnum>("blah");
// OR
SomeEnum blah;
Enums.Parse("blah", out blah);
The second one will infer the type, but like I said, it's ugly.
I don't think there's a way around it. At least not in the way you propose it. The main problem being that since it has to be infered at compile time, if you don't have an explicit return type, then the compiler can't actually infer the return type.
Not using generics. Type inference is a compile-time event. One solution would be to have a generic delegate as you posted. The generic delegate would be faster than a cast.
// if BorrowReader is generic...
public delegate T BorrowReader<T>(IDataReader reader);
public class Foo
{
// ... and Foo.Bar() is also generic
public static T Bar<T>(BorrowReader<T> borrower) { ... }
public void SomeMethod()
{
// this does *not* work (compiler needs more help)
var result1 = Foo.Bar(DoFooBarMagic);
// but instead of this (which works)
var result2 = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
// you can do this (also works)
// which emits the same IL, anyway
var result3 = Foo.Bar<List<string>>(DoFooBarMagic);
}
}
I expect F# can do this. I'm no expert, but F# does use return type type inference (details on MSDN).

Categories

Resources