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>();
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.
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.
Updated the example to support method as parameter which is just demonstating how to call generic delegate as parameter of other method.
class Program
{
public delegate T Transformer<T>(T arg) where T : IComparable;
public static void Transform<T>(T value, Transformer<T> method) where T: IComparable
{
Console.WriteLine(method(value));
}
static void Main(string[] args)
{
Transform(5, Square);
}
static int Square(int x)
{
return x * x;
}
}
I tried the following:
public class Test
{
public interface ISomeClass { }
public class ImplementsSomeClass : ISomeClass { }
public delegate void GenericDelegate<T>() where T : ISomeClass;
public void GenericMethod<T>()
{
// EDIT: returns typeof(ImplementsSomeClass)
var t = typeof(T);
}
public void CheckDelegate(GenericDelegate<ISomeClass> mechanism)
{
// EDIT: call without generic argument since it is already determined
mechanism();
}
public void test()
{
GenericDelegate<ISomeClass> someDelegate = GenericMethod<ImplementsSomeClass>;
CheckDelegate(someDelegate);
}
}
And I have no compilation errors. Is it a runtime problem or did I misunderstand your problem description?