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
Related
I have a list of objects ListOfObjects that are all of the same type, but the specific type is not known (however, I do know all the possible types). There are
many possible types. Each object has the property Name, which is a string of its type. I want do something like the following:
foreach (object elements in ListOfObjects)
{
// Some code here that casts elements into the specific type and pass it into another function
}
I know one way to do this is to use a switch case statement
switch (ListOfObjects[0].Name)
{
case "Type1":
//cast into Type1 and pass into function
case "Type2":
//cast into Type2 and pass into function
default:
//something
break;
}
Is there a cleaner way to do this? Is is possible to store the possible Types in a dictionary and cast from that dictionary?
Pattern Matching
To start I want to present the use of pattern matching in switch statements to work with different types, as follows:
public static double ComputeAreaModernSwitch(object shape)
{
switch (shape)
{
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Rectangle r:
return r.Height * r.Length;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
Example taken from Pattern Matching - C# Guide.
Type Dictionary
With that out of the way, yes, you can write a dictionary... the trouble will be on the type of the items.
We can do this:
Dictionary<Type, Action<object>> dictionary;
// (initialize and populate somewhere else) ...
if (dictionary.TryGetValue(element.GetType(), out var action))
{
action(element);
}
However, here you have to use Action<object> because we need to give a type to the items (and no, we can't say Action<?> - well, we can do Action<dynamic> but you cannot cast Action<someType> to Action<dynamic>), forcing you to cast inside the called method.
We can argue that a cast is a way to tell the compiler that we know something it does not. In this case that we know that that object is actually of a given type.
We could do a bit better/worse, depending on how you look at it...
Dictionary<Type, Delegate> dictionary;
// (initialize and populate somewhere else) ...
if (dictionary.TryGetValue(element.GetType(), out var #delegate))
{
#delegate.DynamicInvoke(element);
}
This is effectively late binding. We do not know the types at compile time... as developer you must ensure you provide a delegate of the correct type. However, if we are already enforcing knowledge that the compiler is unaware of, then this could be acceptable.
We can make a helper method to make it easier:
void SetMethod<T>(Action<T> action)
{
dictionary[typeof(T)] = action;
}
Here the compiler can check the type for the method is correct. Yet, from the point of view of the compiler this information is lost (not available) when you consume the dictionary. It is a kind of type erasure if you will.
Dynamic
Now, if we are forgoing types, we could use dynamic following good answer by TheGeneral.
Addendum: Calling a known method (with MethodInfo)
You can call a method by its name, for example, if you have the following:
class Helper
{
public static void Method(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var methodInfo = typeof(Helper).GetMethod("Method");
// ...
methodInfo.Invoke(null, new object[]{element});
You could then put all your methods in a helper class, and find them by the name (which you could derive from the name of the type).
If you want to call a known method that has a generic parameter, you can use MethodInfo. We need to be aware of whatever or not the method is static, and whatever or not the generic argument is part of the method definition or the declaring type definition...
On one hand, if you have something like this:
class Helper<T>
{
public static void Method(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var helperType = typeof(Helper<>);
// ...
var specificMethodInfo = helperType.MakeGenericType(element.GetType()).GetMethod("Method");
specificMethodInfo.Invoke(null, new object[]{element});
On the other hand, if you have this:
class Helper
{
public static void Method<T>(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var methodInfo = typeof(Helper).GetMethod("Method");
// ...
var specificMethodInfo = methodInfo.MakeGenericMethod(element.GetType());
specificMethodInfo.Invoke(null, new object[]{element});
Note: I pass null as first parameter to invoke. That is the instance on which I am calling the method. None, because they are static. If they aren't then you need an instance... you could try creating one with Activator.CreateInstance, for example.
Addendum: Finding what to call (Type Discovery)
Perhaps you have disparate method to call (they are not the same but with different generic argument), but you do not want to have the trouble of populate the dictionary by hand.
That is where Type Discovery comes in.
To begin with, I suggest to use an attribute, for example:
[AttributeUsage(AttributeTargets.Method)]
public sealed class DataHandlerAttribute : Attribute { }
Then we need a list of the types where we will search. If we will search on a known assembly we could do this:
var assembly = typeof(KnownType).GetTypeInfo().Assembly;
var types = assembly.GetTypes();
Note: if your target platform does not support this (.NET Standard 1.0 to 1.4), you will have to hand code the list of types.
Next, we need a predicate to check if a given type is one of the ones in which we are interested:
bool IsDataHandlerMethod(MethodInfo methodInfo)
{
var dataHandlerAttributes = return (DataHandlerAttribute[])item.GetCustomAttributes(typeof(DataHandlerAttribute), true);
if (attributes == null || attributes.Length == 0)
{
return false;
}
if (methodInfo.DeclaringType != null)
{
return false;
}
if (methodInfo.ReturnTpye != typeof(void))
{
return false;
}
var parameters = methodInfo.GetParameters();
if (parameters.Length != 1)
{
return false;
}
if (paramters[0].IsByRef || paramters[0].IsOut)
{
return false;
}
return true;
}
And a method to convert them into delegates:
(Type, Delegate) GetTypeDelegatePair(MethodInfo methodInfo)
{
var parameters = methodInfo.GetParameters();
var parameterType = parameters[0].ParameterType;
var parameterTypeArray = new []{parameterType};
var delegateType = typeof(Action<>).MakeGenericType(parameterTypeArray);
var target = null;
if (!methodInfo.IsStatic)
{
var declaringType = methodInfo.DeclaringType;
target = instance = Activator.CreateInstance(declaringType);
}
return (parameterType, methodInfo.CreateDelegate(delegateType, target));
}
And now we can do this:
var dataHandlers = types
.SelectMany(t => t.GetTypeInfo().GetMethods())
.Where(IsDataHandlerMethod)
.Select(GetTypeDelegatePair);
And we will have an enumerable of pairs of types and delegate that we can use to populate our dictionary.
Note: the above code still needs some work (for example, could we just call GetParameters once?), and presumes a modern .NET target (extra work is needed to make it work in older platforms). Also notice the code for Type Discovery I present does not handle generic methods, you can check Type.IsGenericTypeDefinition and MethodInfo.IsGenericMethodDefinition... however, I would suggest to avoid them. In fact, it should be easy to modify for the case where you want to put all the methods in a single static class. You may also use a similar approach to get factory methods, for example.
If you have overloads, and you don't want to use a switch, you could use dynamic, however you really need to ask yourself if this is a design problem, and should be solved in a more appropriate way. I.e why do you need to store unrelated types in a list anyway?
public static void Test(Version version)
{
Console.WriteLine("is a version");
}
public static void Test(FormatException formatException)
{
Console.WriteLine("is a formatException");
}
static void Main(string[] args)
{
var list = new List<object>();
list.Add(new Version());
list.Add(new FormatException());
foreach (var item in list)
Test((dynamic)item);
}
Output
is a version
is a formatException
Full Demo Here
Note : this will all break if it can't find an overload. ka-bang! So I don't recommend using it, unless you really need to.
You can actually use standard System properties and methods to achieve your goal.
The first thing to do is get the Type:
var type = System.Type.GetType(elements.Name, false, true);
The false parameter indicates that you do not want to throw an exception on error and the true parameter indicates that you want to ignore case.
Once you have a valid type, you can call System.Activator to create a new instance of the class:
if (type != null) {
var classInstance = System.ServiceActivator.CreateInstance(type);
// Use the instance here
}
Note that this overload of CreateInstance requires a parameterless, public constructor. However, there are other overloads that allow you to pass parameters and access non-public constructors.
You can use Type.GetType method to get the type of object instead of doing a string comparision. Here's the same code:
foreach (var element in ListOfObjects)
{
var type = Type.GetType(element.Name);
if (type == typeof(YOUR_OBJECT_TYPE))
{
// Do Something
}
}
Read more about GetType here
I am not sure if i understand your question clearly but,
maybe it can help you, I don't think you need to keep type in name field since you can get type just like this. And i also don't get why do you want to cast this type again to itself.
foreach (var element in ListOfObjects)
{
var _type = element.getType()
}
and you can just use switch case or if statements for making route.
Surely using dictionary mapping Type and Method is possible:
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
Preloading the dictionary:
static void Action1(Object obj)
{
//do necessary casting here or not
Console.WriteLine("i handle Type1");
}
static void Action2(Object obj)
{
Console.WriteLine("i handle Type2");
}
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
methodMap[typeof(Type1)] = Action1;
methodMap[typeof(Type2)] = Action2;
And use the dictionary:
List<Object> collector = new List<Object>();
collector.Add(new Type1());
collector.Add(new Type2());
methodMap[collector[0].GetType()](collector[0]);
methodMap[collector[1].GetType()](collector[1]);
The type-method map also works for those class who's ancient is different. it would be the key factor you choose this kind method rather overloading or virtual member function.
I would like to dynamically execute a method on a class that uses a generic type, after finding it using reflection (which looks for an interface implementation).
An example of where I am stuck is below. Help is much appreciated.
Setup
public interface IActionRequired<T> where T : class {
void DoThis(T[] receivedObjects);
}
public class BookDetails {
public int BookId { get; set; }
public string BookName { get; set; }
}
public class LibraryBookReturned : IActionRequired<BookDetails>
{
public void DoThis(BookDetails[] receivedObjects)
{
foreach(var book in receivedObjects)
System.Console.WriteLine(book.BookName);
}
}
Example Attempt Using Reflection
Below, I am just using the first implementation but in the real world I'll be using a naming convention to locate the correct implementation.
var assembly = Assembly.GetCallingAssembly();
var listOfImplementations =
GetAllTypesImplementingOpenGenericType(typeof(IActionRequired<>), assembly);
var implementation = listOfImplementations.FirstOrDefault();
var implementationUsesInterface = implementation.GetInterfaces() [0];
var interfaceUsesType = implementationUsesInterface.GetGenericArguments() [0];
I understand that the below will not work (I get an error saying interfaceUsesType is a variable not a type) but it indicates what I would like to do:
var instance =
assembly.CreateInstance(implementation.FullName) as IActionRequired<interfaceUsesType>;
var results = this.CheckForMessages<interfaceUsesType>();
instance.DoThis(results);
You're going to have to emit a run-time type specific version of the generic method. Have a look at the MethodInfo.MakeGenericMethod for that one.
The MakeGenericMethod method allows you to write code that assigns specific types to the type parameters of a generic method definition, thus creating a MethodInfo object that represents a particular constructed method. If the ContainsGenericParameters property of this MethodInfo object returns true, you can use it to invoke the method or to create a delegate to invoke the method.
In short (pseudo) code:
this.GetType()
.GetMethod("CheckForMessages")
.MakeGenericMethod(interfaceUsesType)
.Invoke(this, null);
You can also read up on it here: How To: Call a generic method with a runtime type
#rickvbosch 's answer was (very nearly) what I needed and definitely the right way to go. However, since I was trying to do two things effectively, I've upvoted his answer and added what I did to get things working as the accepted answer to my original problem, using his suggestion.
var instance = Activator.CreateInstance(implementation);
var results = this.GetType()
.GetMethod("CheckForMessages", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(interfaceUsesType)
.Invoke(this, null) as object[];
if(results.Count() > 0)
instance.GetType()
.GetMethod("DoThis")
.Invoke(instance, new object[] {results});
If I have an expression in the form of Expression<Func<Delegate>> is it possible to determine the derived type of the object used to pass in the delegate? Does the expression even contain this information, or is it exclusively representative of the delegate.
A code example should make things clearer.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Sandbox {
public interface IContract {
void Method();
}
public class Concrete : IContract {
public void Method() { }
}
public class Test {
private IContract contract = new Concrete();
private Concrete concrete = new Concrete();
public static string GetFullMethodName(Expression<Func<Action>> expression) {
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
var type = methodInfo.DeclaringType;
var name = methodInfo.Name;
return String.Format("{0}.{1}", type, name);
}
public Test() {
var strConcrete = GetFullMethodName(() => concrete.Method); // Sandbox.Concrete.Method
var strContract = GetFullMethodName(() => contract.Method); // Sandbox.IContract.Method
}
}
}
Is it possible to make () => contract.Method produce
Sandbox.Concrete.Method
Instead of
Sandbox.IContract.Method
Can the expression be altered to support this, or would I be forced to pass an instance of the object as a separate parameter in order to determine it's type?
No, that isn't possible.
The expression tree is built based on compile-time information, and at compile-time, the method being invoked is the virtual IContract.Method. The fact that at runtime, the Concrete.Method is actually invoked is irrelevant - that's handled in the virtual dispatch mechanism and the compiler finished its job long before any of this is decided.
The best you can do is try to emulate virtual dispatch yourself. For example, you could try enumerating the interface implementation on the this instance at runtime, and if you do find a method that matches the interface, you'd return that. However, this is certainly tricky - you need to be able to perfectly emulate the actual virtual dispatch.
Another tricky point is that the way you're trying to get the value is already broken. For example, in my environment, the methodInfoExpression is not a ConstantExpression - it's a field on a closure type. Your "parsing" is very fragile.
That said, it's also kind of unnecessary and overcomplicated - you're trying to receive an expression that returns an action and "steal" the value of the action out of the expression. There's already a simple way of doing that - pass that argument directly. No need to hide it in an expression tree:
public static string GetFullMethodName(Action action)
{
return string.Format("{0}.{1}", action.Method.DeclaringType.Name, action.Method.Name);
}
var strConcrete = GetFullMethodName(concrete.Method).Dump(); // Sandbox.Concrete.Method
var strContract = GetFullMethodName(contract.Method).Dump(); // Sandbox.Concrete.Method
You don't need expressions for things that basic reflection already gives you :)
I have the situation, where I want to call some generic method on another object and get IEnumerable result.
private void SomeFunction(Type type)
{
var method = context.GetType()
.GetMethods()
.FirstOrDefault(_ => _.Name == "GetStorage" && _.IsGenericMethod);
var storage = getStorage.MakeGenericMethod(type)
.Invoke(context, new object[] {})
.AsEnumerable();
//Some magic needed here. Something like Cast<type>,
//but type - variable
//More code ...
}
Could anyone suggest me how to figure out this situation. Thank you.
I have already seen this and similar questions:
Casting Results from Generic Method Invocation?
But they doesn't answer on my question, how to do same, when I don't know type, to which I want to cast, and type is stored as variable.
I can't makeSomeFunction a generic method, because the real situation is that I am iterating some list with System.Type and calling lambda (i. e. SomeFunction) on each element
There are some things you need to do to get what you want. You say you want to have a lambda, but that means that you need to define that lambda, which is on a type you do not know yet. You can redesign your lambda into an interface.
Also, I find it much easier to define a generic class that does exactly what I want. By creating an instance of this class through reflection, and only there, I can implement the rest of the class in a strong typed way. This takes away the 'not knowing what type I have' in most places.
Like this. First, the executor interface:
public interface ISomeFunctionExecutor
{
void Execute(SomeContext context);
}
Then the interface that I need to implement on the entities, which is the lambda so to speak.
public interface IEntityWithSomeFunction
{
void SomeFunction();
}
Now the implementation of the executor.
public class SomeFunctionExecutor<TType> : ISomeFunctionExecutor
{
public void Execute(SomeContext context)
{
var data = context.GetStorage<TType>().Cast<IEntityWithSomeFunction>();
foreach (var item in data)
{
item.SomeFunction();
}
}
}
And finally, the usage of it all:
// Usage:
SomeContext context = new SomeContext();
Type type = typeof(SomeEntity);
var executorType = typeof(SomeFunctionExecutor<>).MakeGenericType(type);
var executor = Activator.CreateInstance(executorType) as ISomeFunctionExecutor;
if (executor != null)
{
executor.Execute(context);
}
Basically the point is: define a generic class to do what you need to do where you do know the type, and create an instance of this class using reflection. It makes it much easier than having a whole method where you do not know the type.
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");
}