Generic delegate instances - c#

I wonder if C# (or the underlying .NET framework) supports some kind of "generic delegate instances": that is a delegate instance that still has an unresolved type parameter, to be resolved at the time the delegate is invoked (not at the time the delegate is created). I suspect this isn't possible, but I'm asking it anyway...
Here is an example of what I'd like to do, with some "???" inserted in places where the C# syntax seems to be unavailable for what I want. (Obviously this code doesn't compile)
class Foo {
public T Factory<T>(string name) {
// implementation omitted
}
}
class Test {
public void TestMethod()
{
Foo foo = new Foo();
??? magic = foo.Factory; // No type argument given here yet to Factory!
// What would the '???' be here (other than 'var' :) )?
string aString = magic<string>("name 1"); // type provided on call
int anInt = magic<int>("name 2"); // another type provided on another call
// Note the underlying calls work perfectly fine, these work, but i'd like to expose
// the generic method as a delegate.
string aString2 = foo.Factory<string>("name 1");
int anInt2 = foo.Factory<int>("name 2");
}
}
Is there a way to actually do something like this in C#? If not, is that a limitation in the language, or is it in the .NET framework?
Edit:
The reason I ask is because I'd like to pass the delegate to a function in another assembly, and don't want to require that other assembly having to reference any particular type (the "Foo" class in my example). I was hoping to bend the standard Func<> delegate in a way so it would fit the "???" part.

This cannot be done, since what you're asking is declaring a variable (magic) of an unclosed generics type.
One can work with unclosed generics but only at the type level, e.g.:
delegate T FactoryDelegate<T>(string name);
var magicType = typeof (FactoryDelegate<>);
and then "close" the type at a later point:
var stringMagic = magicType.MakeGenericType(typeof(string));
Update: that said, here's a sample on how you can use the above technique to also work with unclosed method "types". Still not as elegant as it would be if we could assign unclosed types though..:
public class UnclosedMethod
{
private readonly MethodInfo _method;
public UnclosedMethod(Type type, string method)
{
_method = type.GetMethod(method);
}
public T Invoke<T>(string name)
{
var fact = _method.MakeGenericMethod(typeof(T));
return (T)fact.Invoke(this, new object[] { name });
}
}
And then in code do this:
var magic = new UnclosedMethod(typeof(Foo), "Factory");
var x = magic.Invoke<string>("bar");

An excellent question. First of all, we can observe that C# doesn't allow you to define any delegate type with a generic Invoke method. There is simply no space for the type parameters; the list that comes after the delegate name is used for the parameters of the delegate type itself.
So I went for CIL and generated what should look like a delegate with a generic Invoke:
.class public auto ansi sealed GenericDelegate extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
{
}
.method public hidebysig newslot virtual instance !!T Invoke<T>(!!T arg) runtime managed
{
}
}
To my surprise, C# can actually consume this type without issues – you can create an instance of this type from a generic method (with matching constraints) and the program compiles. However, the result is an invalid CIL, as constructing the delegate uses the ldftn instruction but the generic method has no executable code associated with it, as it is generic.
Even though I couldn't find anything in ECMA-335 that would explicitly prohibit the delegate, the runtime rejects it. The problem is that the runtime attribute on Invoke specifies that the implementation for this method is provided by the runtime, but this isn't supported when the method is generic. While ldftn could be modified to allow generic methods and the implementation of Invoke could be provided in this case, it simply isn't.
I agree however that sometimes this concept is useful. While the runtime will not help you with it, probably the easiest way is to simply use an interface:
class Foo
{
public T Factory<T>(string name)
{
}
}
class FooFactory : IGenericFunc<string>
{
readonly Foo target;
public FooFactory(Foo target)
{
this.target = target;
}
public T Invoke<T>(string name)
{
return target.Factory<T>(name);
}
}
interface IGenericFunc<TArg>
{
T Invoke<T>(TArg arg);
}
Create an interface for every variation of arguments you need, and an implementation for every method you need to call. If you also want to have something akin to Delegate.CreateDelegate, you will most likely have to use System.Reflection.Emit to have it somewhat performant.

Just something like?:
Foo foo = new Foo();
string aString =
foo.GetType().GetMethod("Factory").MakeGenericMethod(string)
.Invoke(foo, new object[] { "name 1" });
int anInt =
foo.GetType().GetMethod("Factory").MakeGenericMethod(int)
.Invoke(foo, new object[] { "name 2" });
Now, if you want to use a delegate you may end up with something like:
public delegate T FactoryDelegate<T>(string name);
Then, you can make a call like:
public TestMethod1(FactoryDelegate<dynamic> factory)
{
object o = factory("name 3");
}

Related

C# Type system support to express types that matches constraints

The problem:
public class Test
{
public void A<T>(T arg)
{
// We have proof it's safe to call B
if (arg is IEquatable<T>)
{
// To call B, something like this needed.
// var arg1 = (T:IEquatable<T>) arg;
// B(arg1)
B(arg); // Error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Test.B<T>(T)'.
// There is no boxing conversion or type parameter conversion from 'T' to 'System.IEquatable<T>'.
}
else
{
C(arg);
}
}
public void B<T>(T arg)
where T: IEquatable<T>
{
// We don't want to loos the original type T that has been passed to A<T>
Console.WriteLine(typeof(T).Name);
}
public void C<T>(T arg)
{
}
}
Do we have any C# language constructs that allows to call more generic method with more restrictions on type, if we have proofs it's safe (Higher Kinder Polymorphism, advanced pattern matching, etc) ?
Do we have any option to make a weird unsafe hack to make unallowed generic method call ?
Looks like we can express the call on IL level (Fody + https://github.com/ltrzesniewski/InlineIL.Fody) or somehow Function Pointers can be used.
(Sure reflection can help, but it's expensive and might cause an issues with the CoreRT native compilation).
Instead of using a type constraint what if your parameter type would be IEquatable<T>?
You don't know anything else about that T type so it isn't worth using it as the parameter type instead of IEquatable<T> type.
class Test
{
public void A<T>(T arg)
{
if (arg is IEquatable<T> equatable)
{
B1(equatable);
}
else
{
C(arg);
}
B1(2);
B2(2);
}
public void B1<T>(IEquatable<T> arg)
{
// This should write the original type T that has been passed to A<T>
// because if a type implements IEquatable<>
// then the type parameter should be the same as the implementing type.
// Just what your type constraint expects, anyway.
Console.WriteLine(typeof(T).FullName);
// But you can also get the real T type by using .GetType() method.
Console.WriteLine(arg.GetType());
// Should output true.
Console.WriteLine(typeof(T) == arg.GetType());
}
// You can keep this method as an overload,
// if you really need it for some reason.
public void B2<T>(T arg) where T : IEquatable<T>
{
B1(arg);
}
public void C<T>(T arg)
{
}
}
To call B, something like this needed.
var arg1 = (T:IEquatable<T>) arg
Yes, that is the core of the problem. And no, such a language feature doesn't exist.
To call B1 as is, you need to structure you solution so that the caller can provide a type that matches its signature. The only alternative is reflection.
So your choices are either to relax the constraints of B1. Perhaps by moving the implementation to a new private method which is easier to call from A. Or overload A<T> so the caller can prove that T:IEquatable<T>.

C# How to Initialize Generic class with object of type "Type"

I recently had this problem.
doSomething(typeof(int));
doSomething(typeof(MyClassA));
doSomething(typeof(MyClassB));
public void doSomething(Type _type)
{
var myGenObj = new MyGenericClass<_type>(); // Error. Really I'd want MyGenericClass<int>, MyGenericClass<MyClassA>, etc depending on what's passed in.
myGenObj.doSomeGenStuff();
// more stuff...
}
I think that this can be done with reflection somehow.. Possibly there's an easier way. I've been somewhat confused on how Type works vs Classes under the covers. Anyways thanks for any help.
Thanks.
You want Type.MakeGenericType and then Activator.CreateInstance... but then calling a method on the newly-created object will be tricky. Ideally you could have a non-generic base class or interface containing those members:
public interface IFoo
{
void CallSomeMethod();
}
public class MyGenericClass<T> : IFoo
{
...
}
// Names changed to be more conventional
public void DoSomething(Type type)
{
var genericType = typeof(MyGenericClass<>).MakeGenericType(type);
var instance = (IFoo) Activator.CreateInstance(genericType);
instance.CallSomeMethod();
}
If you do need to call a method which depends on the type parameter, you'll need to do that with reflection, or with dynamic which can streamline reflection-based code.
EDIT: As cdhowie says, if you always actually do know the type at compile-time, you can use a generic method which would make things much simpler. You'd then call the method like this:
DoSomething<int>();
DoSomething<MyClassA>();
DoSomething<MyClassB>();
Like this:
object myGenObj = Activator.CreateInstance(typeof(MyGenericClass<>).MakeGenericType(_type));
However, since the produced object is of a type that you don't know at compile-time, you can't really invoke members of the object through the generic type (except via reflection). If there is an ancestor type or implemented interface that you do know of at compile-time, you can cast to that and then invoke the member.
You might also consider wrapping this functionality in a generic method, which makes the whole thing easier to deal with:
public void doSomething<T>()
{
var myGenObj = new MyGenericClass<T>();
myGenObj.doSomeGenStuff();
}
If you have to support Type objects you can use an overload that cheats using reflection:
public void doSomething(Type _type)
{
this.GetType().GetMethod("doSomething", Type.EmptyTypes)
.MakeGenericMethod(_type)
.Invoke(this, null);
}

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

Internal Workings of C# Virtual and Override

The topic of how C# virtual and override mechanism works internally has been discussed to death amongst the programmers... but after half an hour on google, I cannot find an answer to the following question (see below):
Using a simple code:
public class BaseClass
{
public virtual SayNo() { return "NO!!!"; }
}
public class SecondClass: BaseClass
{
public override SayNo() { return "No."; }
}
public class ThirdClass: SecondClass
{
public override SayNo() { return "No..."; }
}
class Program
{
static void Main()
{
ThirdClass thirdclass = new ThirdClass();
string a = thirdclass.SayNo(); // this would return "No..."
// Question:
// Is there a way, not using the "new" keyword and/or the "hide"
// mechansim (i.e. not modifying the 3 classes above), can we somehow return
// a string from the SecondClass or even the BaseClass only using the
// variable "third"?
// I know the lines below won't get me to "NO!!!"
BaseClass bc = (BaseClass)thirdclass;
string b = bc.SayNo(); // this gives me "No..." but how to I get to "NO!!!"?
}
}
I think I can't get to the methods of base class or the intermediate derived class simply using the most derived instance (without modifying the method signatures of the 3 classes). But I would like to confirm and cement my understanding...
Thanks.
C# can't do this but it is actually possible in IL using call instead of callvirt. You can thus work around C#'s limitation by using Reflection.Emit in combination with a DynamicMethod.
Here's a very simple example to illustrate how this works. If you really intend to use this, wrap it inside a nice function strive to make it work with different delegate types.
delegate string SayNoDelegate(BaseClass instance);
static void Main() {
BaseClass target = new SecondClass();
var method_args = new Type[] { typeof(BaseClass) };
var pull = new DynamicMethod("pull", typeof(string), method_args);
var method = typeof(BaseClass).GetMethod("SayNo", new Type[] {});
var ilgen = pull.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.EmitCall(OpCodes.Call, method, null);
ilgen.Emit(OpCodes.Ret);
var call = (SayNoDelegate)pull.CreateDelegate(typeof(SayNoDelegate));
Console.WriteLine("callvirt, in C#: {0}", target.SayNo());
Console.WriteLine("call, in IL: {0}", call(target));
}
Prints:
callvirt, in C#: No.
call, in IL: NO!!!
Without modification to your sample and discounting reflection, no there is no way. The intent of the virtual system is to enforce calling the derived most no matter what and the CLR is good at its job.
There are a couple of ways you can work around this though.
Option 1: You could add the following method to ThirdClass
public void SayNoBase() {
base.SayNo();
}
This would force the invocation of SecondClass.SayNo
Option 2: The main problem here is that you want to invoke a virtual method non-virtually. C# only provides one way of doing this via the base modifier. This makes it impossible to call a method within your own class in a non-virtual fashion. You can fix this by factoring it out into a second method and proxying.
public overrides void SayNo() {
SayNoHelper();
}
public void SayNoHelper() {
Console.WriteLine("No");
}
Sure...
BaseClass bc = new BaseClass();
string b = bc.SayNo();
"Virtual" means that the implementation which will be executed is based on the ACTUAL type of the underlying object, not the type of the variable it is stuffed in... So if the actual object is a ThirdClass, that's the implementation you will get, no matter what you cast it to. If you want the behavior you describe above, don't make the methods virtual...
If you're wondering "what's the point?" it's for 'polymorphism'; so that you can declare a collection, or a method parameter, as some base type, and include/ pass it a mix of derived types, and yet when, within the code, even though each object is assigned to a ref variable declared as the base type, for each one, the actual implementation which will be executed for any virtual method call will be that implementation defined in the class definition for the ACTUAL tyoe of each object...
Using base in C# only works for the immediate base. You can't access a base-base member.
It looks someone else beat me to the punch with the answer about it being possible to do in IL.
However, I think the way I did the code gen has some advantages, so I'll post it anyways.
The thing I did differently is to use expression trees, which enable you to use the C# compiler to do overload resolution and generic argument substitution.
That stuff is complicated, and you don't want to have to replicate it your self if you can help it.
In your case, the code would work like this:
var del =
CreateNonVirtualCall<Program, BaseClass, Action<ThirdClass>>
(
x=>x.SayNo()
);
You would probably want to store the delegate in a readonly static field, so that you only have to compile it once.
You need to specify 3 generic arguments:
The owner type - This is the class that you would have invoked the code from if you were not using "CreateNonVirtualCall".
The base class - This is the class you want to make the non virtual call from
A delegate type. This should represent the signature of the method being called with an extra parameter for the "this" argument. It's possible to eliminate this, but it requires more work in the code gen method.
The method takes a single argument, a lambda representing the call. It has to be a call, and only a call. If you want to extend the code gen you can support more complex stuff.
For simplicicty, the lambda body is restricted to only being able to access lambda parameters, and can only pass them in directly to the function. You can remove this restriction if you extend the code gen in the method body to support all expression types. That would take some work though. You can do anything you want with the delegate that comes back, so the restriction isn't too big of a deal.
It's important to note that this code is not perfect. It could use a lot more validation, and it doesn't work with "ref" or "out" parameters because of expression tree limitations.
I did test it in sample cases with void methods, methods returning values, and generic methods, and it worked. I'm sure, however, you can find some edge cases that don't work.
In any case, here's the IL Gen Code:
public static TDelegate CreateNonVirtCall<TOwner, TBase, TDelegate>(Expression<TDelegate> call) where TDelegate : class
{
if (! typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new InvalidOperationException("TDelegate must be a delegate type.");
}
var body = call.Body as MethodCallExpression;
if (body.NodeType != ExpressionType.Call || body == null)
{
throw new ArgumentException("Expected a call expression", "call");
}
foreach (var arg in body.Arguments)
{
if (arg.NodeType != ExpressionType.Parameter)
{
//to support non lambda parameter arguments, you need to add support for compiling all expression types.
throw new ArgumentException("Expected a constant or parameter argument", "call");
}
}
if (body.Object != null && body.Object.NodeType != ExpressionType.Parameter)
{
//to support a non constant base, you have to implement support for compiling all expression types.
throw new ArgumentException("Expected a constant base expression", "call");
}
var paramMap = new Dictionary<string, int>();
int index = 0;
foreach (var item in call.Parameters)
{
paramMap.Add(item.Name, index++);
}
Type[] parameterTypes;
parameterTypes = call.Parameters.Select(p => p.Type).ToArray();
var m =
new DynamicMethod
(
"$something_unique",
body.Type,
parameterTypes,
typeof(TOwner)
);
var builder = m.GetILGenerator();
var callTarget = body.Method;
if (body.Object != null)
{
var paramIndex = paramMap[((ParameterExpression)body.Object).Name];
builder.Emit(OpCodes.Ldarg, paramIndex);
}
foreach (var item in body.Arguments)
{
var param = (ParameterExpression)item;
builder.Emit(OpCodes.Ldarg, paramMap[param.Name]);
}
builder.EmitCall(OpCodes.Call, FindBaseMethod(typeof(TBase), callTarget), null);
if (body.Type != typeof(void))
{
builder.Emit(OpCodes.Ret);
}
var obj = (object) m.CreateDelegate(typeof (TDelegate));
return obj as TDelegate;
}
You can't get to the base methods of an override. No matter how you cast the object, the last override in the instance is always used.
If its backed with a field you could pull out the field using reflection.
Even if you pull off the methodinfo using reflection from typeof(BaseClass) you will still end up executing your overridden method

Calling a static method on a generic type parameter

I was hoping to do something like this, but it appears to be illegal in C#:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
I get a compile-time error:
'T' is a 'type parameter', which is not valid in the given context.
Given a generic type parameter, how can I call a static method on the generic class? The static method has to be available, given the constraint.
In this case you should just call the static method on the constrainted type directly. C# (and the CLR) do not support virtual static methods. So:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
...can be no different than:
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
Going through the generic type parameter is an unneeded indirection and hence not supported.
To elaborate on a previous answer, I think reflection is closer to what you want here. I could give 1001 reasons why you should or should not do something, I'll just answer your question as asked. I think you should call the GetMethod method on the type of the generic parameter and go from there. For example, for a function:
public void doSomething<T>() where T : someParent
{
List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
//do something with items
}
Where T is any class that has the static method fetchAll().
Yes, I'm aware this is horrifically slow and may crash if someParent doesn't force all of its child classes to implement fetchAll but it answers the question as asked.
You can do what I call a surrogate singleton, I've been using it as a sort of "static inheritance" for a while
interface IFoo<T> where T : IFoo<T>, new()
{
ICollection<T> ReturnsCollection();
}
static class Foo<T> where T : IFoo<T>, new()
{
private static readonly T value = new();
public static ICollection<T> ReturnsCollection() => value.ReturnsCollection();
}
// Use case
public ICollection<T> DoSomething<T>() where T : IFoo<T>, new()
{
return Foo<T>.ReturnsCollection();
}
The only way of calling such a method would be via reflection, However, it sounds like it might be possible to wrap that functionality in an interface and use an instance-based IoC / factory / etc pattern.
It sounds like you're trying to use generics to work around the fact that there are no "virtual static methods" in C#.
Unfortunately, that's not gonna work.
I just wanted to throw it out there that sometimes delegates solve these problems, depending on context.
If you need to call the static method as some kind of a factory or initialization method, then you could declare a delegate and pass the static method to the relevant generic factory or whatever it is that needs this "generic class with this static method".
For example:
class Factory<TProduct> where TProduct : new()
{
public delegate void ProductInitializationMethod(TProduct newProduct);
private ProductInitializationMethod m_ProductInitializationMethod;
public Factory(ProductInitializationMethod p_ProductInitializationMethod)
{
m_ProductInitializationMethod = p_ProductInitializationMethod;
}
public TProduct CreateProduct()
{
var prod = new TProduct();
m_ProductInitializationMethod(prod);
return prod;
}
}
class ProductA
{
public static void InitializeProduct(ProductA newProduct)
{
// .. Do something with a new ProductA
}
}
class ProductB
{
public static void InitializeProduct(ProductB newProduct)
{
// .. Do something with a new ProductA
}
}
class GenericAndDelegateTest
{
public static void Main()
{
var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);
ProductA prodA = factoryA.CreateProduct();
ProductB prodB = factoryB.CreateProduct();
}
}
Unfortunately you can't enforce that the class has the right method, but you can at least compile-time-enforce that the resulting factory method has everything it expects (i.e an initialization method with exactly the right signature). This is better than a run time reflection exception.
This approach also has some benefits, i.e you can reuse init methods, have them be instance methods, etc.
You should be able to do this using reflection, as is described here
Due to link being dead, I found the relevant details in the wayback machine:
Assume you have a class with a static generic method:
class ClassWithGenericStaticMethod
{
public static void PrintName<T>(string prefix) where T : class
{
Console.WriteLine(prefix + " " + typeof(T).FullName);
}
}
How can you invoke this method using relection?
It turns out to be very easy… This is how you Invoke a Static Generic
Method using Reflection:
// Grabbing the type that has the static generic method
Type typeofClassWithGenericStaticMethod = typeof(ClassWithGenericStaticMethod);
// Grabbing the specific static method
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethod("PrintName", System.Reflection.BindingFlags.Static | BindingFlags.Public);
// Binding the method info to generic arguments
Type[] genericArguments = new Type[] { typeof(Program) };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
// Simply invoking the method and passing parameters
// The null parameter is the object to call the method from. Since the method is
// static, pass null.
object returnValue = genericMethodInfo.Invoke(null, new object[] { "hello" });
As of now, you can't. You need a way of telling the compiler that T has that method, and presently, there's no way to do that. (Many are pushing Microsoft to expand what can be specified in a generic constraint, so maybe this will be possible in the future).
Here, i post an example that work, it's a workaround
public interface eInterface {
void MethodOnSomeBaseClassThatReturnsCollection();
}
public T:SomeBaseClass, eInterface {
public void MethodOnSomeBaseClassThatReturnsCollection()
{ StaticMethodOnSomeBaseClassThatReturnsCollection() }
}
public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{
return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}

Categories

Resources