Passing Delegate object to method with Func<> parameter - c#

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 :)

Related

C# infer Type from Generic with constraint

I'm trying to register a generic that derives from a base class in the following way, but getting the error :
cannot convert MyCallback<T> expression to type MyCallback<Event>
I was hoping the constraints would make this possible but am I missing something?
public class Event
{ };
public delegate void MyCallback<T>(T arg1) where T : Event;
static class EventDispatcher
{
public static Dictionary<string, MyCallback<Event>> eventTable = new Dictionary<string, MyCallback<Event>>();
static void RegisterCallback<T>(MyCallback<T> callback) where T : Event
{
eventTable.Add("test", callback);
}
}
When you have a MyCallback<Event> you're saying that you have a method that can take any type of event. It can accept an EventOne, or an EventTwo, or a SomeOtherEvent.
Let's say I call RegisterCallback and pass in a delegate pointing to a method with this signature:
public static void Foo(SomeOtherEvent arg)
If your code would work, and I could assign that to a MyCallback<Event>, then I could pass in an EventOne instance to that method when calling it. That's obviously a problem.
There's a term for that; you're expecting MyCallback to be covariant with respect to it's generic argument. In fact, it's contravariant. If I have a method that can accept any type of event, I can clearly pass in a SomeEvent, or a SomeOtherEvent, meaning I could assign a MyCallback<Event> to a MyCallback<SomeOtherEvent>, rather than the other way around.
If you want to tell the compiler that, "I know that this method cannot actually be called with any type of event, but I want you to allow this check and only fail at runtime if the given argument is not of the proper type." then you can do that, assuming you actually have a way of ensuring you call each callback with the proper arguments. You can't just do a cast either; you need to wrap the method in a new method that does the cast:
eventTable.Add("test", e => callback((T)e));
You need to have the type parameter be part of the EventDispatcher class:
public class EventDispatcher<T> : where T : Event {
public Dictionary<string, MyCallback<T>> eventTable = new Dictionary<string, MyCallback<T>>();
void RegisterCallback(MyCallback<T> callback) {
eventTable.Add("test", callback);
}
}
This is because the MyCallback<Event> declared in eventTable is not going to be compiled into the same type declared in RegisteredCallback when written like your example.

Passing a generic function as a parameter

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);
}

How does generic type inference work in C#?

If I have the following code
private BaseMessage getMessage()
{
return new OtherMessage();
}
private void CheckType<T>(T type)
{
Console.WriteLine(type.GetType().ToString());
Console.WriteLine(typeof(T).ToString());
}
private void DoChecks()
{
BaseMessage mess = getMessage();
CheckType(mess);
}
why do I get different types outputted? Is there anyway of getting the type inference to use the actual type of the object being passed?
Generic type inference means that the compiler automatically resolves the types of the arguments being passed without the need of you explicitly specifying what type you're passing. This means that this is done in compile-time: in your code, during the compilation, the compiler only knows about BaseMessage, so the parameter will be passed as BaseMessage. During the run-time, the parameter's actual type will be OtherMessage, but that is of no concern to the compiler.
Therefore, the output you're getting is absolutely valid. I don't know any ways do overcome this issue, apart from always using Object.GetType instead of typeof().
The reason is that you've declared the variable mess as being of type BaseMessage. So when you ask for the type, it's returning BaseMessage.
It's a difference between the way that GetType and typeof behave. GetType returns the actual type of the object at run-time, which can be different from the type of the variable that references the object if inheritance is involved (as is the case in your example). Unlike GetType, typeof is resolved at compile-time to a type literal of the exact type specified.
public class BaseMessage { }
public class OtherMessage : BaseMessage { }
private BaseMessage getMessage()
{
return new OtherMessage();
}
private void CheckType<T>(T type)
{
Console.WriteLine(type.GetType().ToString()); // prints OtherMessage
Console.WriteLine(typeof(T).ToString()); // prints BaseMessage
}
private void DoChecks()
{
BaseMessage mess = getMessage();
CheckType(mess);
}
You have to choose the right tool for the job. Use typeof when you want to get the type at compilation time. Use GetType when you want to get the run-time type of an object.

Delegate Covariance Confusion Conundrum!

Why does this not work? Do I not understand delegate covariance correctly?
public delegate void MyDelegate(object obj)
public class MyClass
{
public MyClass()
{
//Error: Expected method with 'void MyDelegate(object)' signature
_delegate = MyMethod;
}
private MyDelegate _delegate;
public void MyMethod(SomeObject obj)
{}
}
Correct - you don't understand covariance correctly - yet :) Your code would work if you had the same types but as return values, like this:
public delegate object MyDelegate()
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate _delegate;
public SomeObject MyMethod() { return null; }
}
That would demonstrate covariance. Alternatively, you can keep it as parameters but switch the types around:
public delegate void MyDelegate(SomeObject obj)
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate _delegate;
public void MyMethod(object obj) {}
}
This now demonstrates contravariance.
My rule of thumb is to ask myself, "given the delegate, what could I do with it? If I can pass in an argument which would break the method, the conversion should have failed. If the method can return something which would break the caller, the conversion should have failed."
In your code, you could have called:
_delegate(new object());
At that point, poor MyMethod has a parameter which is meant to be of type SomeObject, but is actually of type object. This would be a Very Bad Thing, so the compiler stops it from happening.
Does that all make more sense?
Arguments are contravariant, return types are covariant. If the delegate were to be called with an object that is not an instance of SomeObject, you'd have a typing error. On the other hand, returning SomeObject from a routine wrapped in a delegate that returns object is fine.
You need to use a generic.
EDIT: Why? Because as another poster
noted, Object and SomeObject do not
equate to the same thing as Object may
not be SomeObject. This is the whole
point of Generics in the language.
public delegate void MyDelegate<T>(T obj)
public class MyClass
{
public MyClass()
{
_delegate = MyMethod;
}
private MyDelegate<SomeObject> _delegate;
public void MyMethod(SomeObject obj)
{
}
}
The MyDelegate type declares that you can pass any kind of object in. However, MyMethod only takes objects of type SomeObject. What happens if I try to invoke the delegate passing a different kind of object: _delegate("a string object")? According to the declaration of MyDelegate, this should be allowed, but your function MyMethod can't actually receive a string argument.
From the MSDN link you provided
Covariance permits a method to have a
more derived return type than what is
defined in the delegate.
Contravariance permits a method with
parameter types that are less derived
than in the delegate type.
You're attempting to use a more derived parameter type which isn't supported (although .NET 4.0 probably will since this has sorted out many covariance/contravariance issues).
Covariance and Contravariance is about understanding the Is-a-Principle of inheritance.
In both, covariance and contravariance, s.th. is "passed along", either as return value or as an argument to the delegate method. That which is "passed along" has to be "caught" in a receptacle. In C# – or programming jargon as such – we use the word bucket for what I called receptacle. Sometimes you have to fall back to other words in order to catch the meaning of commonly used jargon words.
Anyway, if you understand inheritance, which most likely any reader here will, then the only thing to pay attention to is that the receptacle, i. e. the bucket used for catching has to be of the same type or less derived type than that which is being passed – this being true for both covariance and contravariance.
Inheritance says you can catch a bird in an animal bucket because the bird is an animal. So if a parameter of a method has to catch a bird you could catch it in an animal bucket (a parameter of type animal), which then is contravariance.
And if your method, i.e. your delegate returns a bird, then the "bucket" also can be a of type bird or less derived (of a parent type) meaning the variable where you catch the return value of the method has to be of the same or less derived type than the return value.
Just switch your thinking to discriminate between that which is being passed and that which catches as then all complexity about covariance and contravariance dissolves nicely. Then you realize that the same principle is at work. It is just that inheritance cannot be violated as it flows only one way.
And the compiler is so smart that when you cast the bucket in the more specialized type (again, and as need be) that then and only then you get all the specialized methods back that were added into the more derived class. That is the beauty of it. So it is catch, cast and use what you have and perhaps need.

What are the advantages of using generics in method signatures?

(Thanks everyone for the answers, here is my refactored example, in turn another StackOverflow question about the Single Responsibility Principle.)
Coming from PHP to C#, this syntax was intimidating:
container.RegisterType<Customer>("customer1");
until I realized it expresses the same thing as:
container.RegisterType(typeof(Customer), "customer1");
as I demonstrate in the code below.
So is there some reason why generics is used here (e.g. throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, i.e. you don't need the typeof() when sending the type?
using System;
namespace TestGenericParameter
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
container.RegisterType<Customer>("test");
container.RegisterType(typeof(Customer), "test");
Console.ReadLine();
}
}
public class Container
{
public void RegisterType<T>(string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
}
public void RegisterType(Type T, string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
}
}
public class Customer {}
}
//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method.
That means, you can write methods like
public T GetAs<T>(string name)
where the return type can be checked by the compiler and boxing value types can sometimes be avoided.
The caller would write:
int value = GetAs<int>("foo");
Whithout generics, you would have to write
public object GetAs(Type t, string name)
and the caller has to cast the result again:
int value = (int)GetAs(typeof(int), "foo");
A primary reason is the type safety at compile time. If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.
This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.
public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}
This code will only work if TConcrete is implementing or inheriting TAbstract. If this method took two Type parameters, your method should validate this relationship.
A simple answer is type inference where possible.
If the generic type is used in the method signature, you can omit it because the type could be inferred:
void SomeMethod<T>(T x, T y) where T : IComparable<T> {
Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}
So the usage is simplified:
SomeMethod(3, 4); // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");
If the generic type parameter is not used in the method signature the type inference is not possible:
var emptySequence = Enumerable.Empty<int>();
I think one of the primary uses is type safety with arguments and return values. In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).
A more appropriate use might be:
public T RegisterType<T>(string name)
{
T obj = new T();
obj.DoSomething();
return obj;
}
or maybe
public void DoSomething<T>(T obj)
{
//operate on obj
}
If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.
For one example, compare the code needed to create an instance of your type using the typeof option versus a generic. Or return an instance of the type. Or accept an instance of the type as an argument. Or set a property on an instance of the type.
In general, if you will be working only with the type itself you can accept a type parameter. If you want to do anything with an instance of the type, use a generic.
Another reason to use a generic is if you want to apply constraints to the type. For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above. The compiler will enforce this so you can't build code that doesn't comply with your requirements.
I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor). Using "typeof" will let you send anything through.

Categories

Resources