Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Method assigned to Delegate

I've been a little puzzled with Delegates and Generic Methods.

Is it possible to assign a delegate to a method with a generic type parameter?

I.E:

//This doesn't allow me to pass a generic parameter with the delegate.
public delegate void GenericDelegate<T>() 

someDelegate = GenericMethod;
public void GenericMethod<T>() where T : ISomeClass
{

}

I'm trying to pass this delegate into the function with a generic type of the interface that the method is expecting, with a function like this:

void CheckDelegate(GenericDelegate<ISomeClass> mechanism);

so that I can use the delegate like so:

someDelegate<ImplementsSomeClass>();
like image 205
10001110101 Avatar asked Dec 08 '13 03:12

10001110101


People also ask

Can delegates be used with generic types?

Delegates defined within a generic class can use the generic class type parameters in the same way that class methods do. Generic delegates are especially useful in defining events based on the typical design pattern because the sender argument can be strongly typed and no longer has to be cast to and from Object.

What is generic delegate?

Func is generic delegate present in System namespace. It takes one or more input parameters and returns one out parameter. The last parameter is considered as a return value. Func delegate type can include 0 to 16 input parameters of different types. It must have one return type.

Which of the following are generic delegates?

Func, Action, and Predicate are Generic Inbuilt delegates that are present in the System namespace which is introduced in C# 3. All these three delegates can be used with the method, Anonymous Method, and Lambda Expressions in C#.

How do you assign a delegate to a function?

Delegates can be invoke like a normal function or Invoke() method. Multiple methods can be assigned to the delegate using "+" or "+=" operator and removed using "-" or "-=" operator. It is called multicast delegate. If a multicast delegate returns a value then it returns the value from the last assigned target method.


2 Answers

Your question makes no sense because you can't ever use an open generic type to declare a storage location (like a local variable or field). It must always be closed.

I understand you want to pass a GenericDelegate<T> to a method taking such a value as an argument. But even then the delegate type becomes closed with T as the generic type parameter.

In your sample code you write

someDelegate = GenericMethod;

but what type is someDelegate supposed to have? It must either be obviously closed (GenericDelegate<string>) or closed with a generic type parameter from the outer scope:

void SomeOuterMethod<T>() where T : ISomeClass {
    GenericDelegate<T> someDelegate = GenericMethod<T>;
}

I hope I understood your problem. If not, please clarify. If you elaborate a little on what you want to accomplish I'll try to suggest a practical solution.

Other languages like Haskell do have support for passing around values of open generic types (in other words, you can have a variable of type IEnumerable<>). This is required to implement monads. The CLR does not have that feature.


New thought: instead of a delegate you could create a non-generic base type with a generic method that can be overridden:

interface CheckHandler {
 public void Check<T>(T someArg);
}

Hope that covers your scenario. You can not freely pass any CheckHandler around. Its Check method can then be called with an arbitrary type argument.

like image 127
usr Avatar answered Sep 23 '22 16:09

usr


It is possible to have a single "thing" which can operate upon multiple parameter types, but the Delegate class is not suitable for that. Instead, you'll need to define an interface. As a simple example:

public interface IMunger<TConstraint>
{
    void Munge<T>(ref T it) where T : TConstraint;
}
public class Cloner : IMunger<ICloneable>
{
    public void Munge<T>(ref T it) where T : ICloneable
    {
        if (typeof(T).IsValueType) // See text
            return;
        it = (T)(it.Clone());
    }
}

Even if the system had a pre-defined delegate type with a by-ref parameter (so that e.g. ActByRef<ICloneable> would have signature void Invoke(ref ICloneable p1)) such a delegate only be used on a variable of exact type ICloneable. By contrast, a single object of non-generic class type Cloner is able to provide a method suitable for use with any storage location type which implements ICloneable. Note also that if the method is passed a ref to a variable holding a reference to a boxed value-type instance, it will replace it with a reference to a copy of the instance, but if it is passed a ref to a value-type variable, it leave it as is (unless the value-type holds its state in a mutable class object to which it holds a reference--a very dodgy pattern--saying StructType foo = (StructType)(bar.Clone()); would be equivalent to just foo = bar; the structure type may want to implement ICloneable so to allow it to take part in a deep-cloning hierarchy, but that doesn't mean its Clone method needs to do anything.

like image 25
supercat Avatar answered Sep 24 '22 16:09

supercat