How does func ACTUALLY work - c#

So when I return an object, under the covers I think it's returning the memory address to that object (or an object containing the memory address) which you can reference and use.
But what is actually happening when you return a func?
How does your app know which instance of an object to use with that func?
My instinct tells me that an object instance reference is passed along with the func but is that what is actually happening?
I can't seem to find much on this topic.
Edit:
To clarify, I am asking when a method returns a func

A Func is a delegate -- a type of object that is associated with a specific method signature and is usually bound to a specific method with that signature. This might be either a static or an instance method and it might be generic or not; in all cases, the delegate instance holds all the information required to call the method.

A Func is a delegate, and Delegate instances encapsulate a MethodInfo and an optional target object to invoke the method on when invoked.

Func<T> is just a delegate. If it is set to an instance method, then, it [magically] gets the correct this value when invoked. If set to a static method, then there is no this. And if it's set to a closure/lambda, the closure "captures" those variables in scope at the time of closure. lexical scope (with some caveats: things don't always work the way you think they might).
Edited to add:
From the C# standard, ISO 23270:2006 Information Technology — Programming Languages — C#, §8.10:
8.10 Delegates
Delegates enable scenarios that some other languages have addressed with function
pointers. However, unlike function pointers, delegates are object-oriented and type-safe.
A delegate declaration defines a class that is derived from the class System.Delegate.
A delegate instance encapsulates one or more methods, each of which is referred to as
a callable entity. For instance methods, a callable entity consists of an instance
and a method on that instance. For static methods, a callable entity consists of just
a method. Given a delegate instance and an appropriate set of arguments, one can invoke
all of that delegate instance’s methods with that set of arguments.
In more detail, the other standard, ISO 23271:2006 Information Technology — Common Language Infrastructure (CLI) Partitions I to VI says in §14.6:
The instance constructor (named .ctor and marked specialname and rtspecialname,
see §10.5.1) shall take exactly two parameters, the first having type System.Object,
and the second having type System.IntPtr. When actually called (via a newobj
instruction, see Partition III), the first argument shall be an instance of the class
(or one of its derived classes) that defines the target method, and the second argument
shall be a method pointer to the method to be called.
It's not that magic.

When you create an anonymous method, such as one assigned to a Func<T>, locals used inside of it are lifted into a class. Consider this:
int GetIncremented()
{
int x = 0;
Func<int> increment = () => ++x;
increment();
return x;
}
Behind the scenes, something like this will be created:
sealed class FuncData
{
public int x = 0;
public int FuncIncrement(FuncData data)
{
return ++data.x;
}
}
int GetIncremented()
{
FuncData data = new FuncData();
Func<int> increment = new Func<int>(data.FuncIncrement);
increment();
return data.x;
}
This is why out and ref parameters can't be used with anonymous methods: you can't store an out or ref as a member variable in a class.

You have both Func and Action, which are in-built delegates. The difference between these is that Func returns a type and Action does not.
You'll find Func uses heavily in the IEnumerable(T) Interface, with Linq extension methods.
Take a look at this example from the MSDN link provided...
Func<string, string> selector = str => str.ToUpper();
string[] words = { "orange", "apple", "Article", "elephant" };
IEnumerable<String> aWords = words.Select(selector);
foreach (String word in aWords)
Console.WriteLine(word);
This essentially uses the Selector Func to convert each of the strings in words to upper case.

Related

Why does .NET List Sort() not take an explicitly declared delegate object?

Quick question.
In the second example on this documentation page (the second code block, featuring a method called CompareDinosByLength), the Sort method is called as such:
dinosaurs.Sort(CompareDinosByLength);
Why is it that the Sort method didn't need an explicitly declared delegate, as I would have thought by reading the Delegate documentation? Before I found that example, I was attempting to do it like so:
delegate int CompareDinosDel(string first, string second);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
But I kept getting errors related to the delegate / delegate method not being proper Comparers.
Shouldn't both work?
Why is it that the Sort method didn't need an explicitly declared delegate?
C# permits a method group -- that is, a method which is named without having the (...) argument list to invoke it -- to be used in a context where a delegate is expected. The compiler performs overload resolution on the method group as though the method group had been invoked with arguments of the types of the delegate's formal parameters. This determines which method of the method group should be used to create the delegate.
This overload resolution process can sometimes lead to unusual situations involving method type inference when the method group is undergoing overload resolution to a delegate type which is a formal parameter type of a generic method; Sort, fortunately is not a generic method, so these oddities do not come into play.
This feature was added to C# 2.0; before that a method group had to be converted to a delegate via
new MyDelegate(MyMethod)
I keep getting errors related to the delegate / delegate method not being proper Comparers. Shouldn't both work?
Unfortunately, no. C# does not have structural identity on delegate types. That is:
delegate void Foo();
delegate void Bar();
...
Foo foo = ()=>{};
Bar bar = foo; // ERROR!
Even though Foo and Bar are structurally identical, the compiler disallows the conversion. You can however use the previous trick:
Bar bar = foo.Invoke;
This is equivalent to
Bar bar = new Bar(foo.Invoke);
However the new bar has as its action to invoke foo; it goes through a level of indirection.
This feature does make some sense.
Reason one:
You don't expect structural identity to work in other places:
struct Point { int x; int y; ... }
struct Pair { int key; int value; ... }
....
Point point = whatever;
Pair pair = point; // ERROR
Reason two:
You might want to say:
delegate int PureMethod(int);
And have a convention that PureMethod delegates are "pure" -- that is, the methods they represent do not throw, always return, return a value computed only from their argument, and produce no side effects. It should be an error to say
Func<int, int> f = x => { Console.WriteLine(x); return x+1; };
PureMethod p = f;
Because f is not pure.
However in hindsight people do not actually make semantics-laden delegates. It is a pain point that a value of type Predicate<int> cannot be assigned to a variable of type Func<int, bool> and vice versa.
If we had to do it all over again, I suspect that delegates would have structural identity in the CLR.
Finally, I note that VB is much more forgiving about inter-assigning mixed delegate types; it automatically builds an adapter delegate if it needs to. This can be confusing because sometimes it looks like referential identity is maintained when in fact it is not, but this is in keeping with the VB philosophy of "just make my code work".
dinosaurs.Sort(CompareDinosByLength);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
Shouldn't both work?
No, because you are passing two very different things into those two function calls.
The key here is to recognize that, in both cases, what you actually pass into the method is a delegate. In the first case, the compiler is implicitly creating a delegate of the correct type for you, even though you didn't explicitly ask it to. In the second case, you're making your own delegate, but it's the wrong type, so that attempt will fail.
Starting with .NET 2.0, the C# compiler allow you to skip explicitly create delegates in many situations. If you use a method name in a context where a delegate is expected, and the compiler can verify that the method signature and delegate signature match, it will implicitly construct a delegate instance using the method. That is, instead of doing this (the "old" way)
this.SubmitButton.Click += new System.EventHandler(this.SubmitButton_Click);
You can now do this:
this.SubmitButton.Click += this.SubmitButton_Click;
Visual Studio itself will still generate the older syntax, I assume because it still works and because it's not worth the developer's time to go messing around with it for very little benefit. However, most popular code analysis tools will flag the redundant delegate creation if you use it in your own code.
This same technique works anywhere you have a method (technically a "method group", since one method name can refer to more than one overload), and you assign it to a variable of a delegate type. Passing a method as a parameter into another method is the same type of assignment operation: you are "assigning" the actual parameter at the call site to the formal parameter in the method body, so the compiler does the same thing. In other words, the following two method calls do exactly the same thing:
dinosaurs.Sort(CompareDinosByLength);
dinosaurs.Sort(new Comparison<string>(CompareDinosByLength));
Your unsuccessful attempt to make a delegate, on the other hand, did something slightly different:
dinosaurs.Sort(new CompareDinosDel(CompareDinosByLength));
This time, you told the compiler exactly what kind of delegate you wanted, but that's not the kind of delegate that the method expected. In general, the compiler isn't going to try to second guess what you told it do to; if you ask it to do something that looks "fishy", it will produce an error (in this case, a type mismatch error).
This behavior is similar to what would happen if you tried to do this:
public class A
{
public int x;
}
public class B
{
public int x;
}
public void Foo(A a) { }
public void Bar()
{
B b = new B();
this.Foo(b);
}
In this case, A and B are two distinct types, even though their "type signature" is exactly the same. Any line of code that works on an A will also work equally well on a B, but yet, we cannot use them interchangeably. Delegates are types like any other types, and C#'s type safety rules require that we use the correct delegate types where we need them, and can't get away with just using a close enough type.
The reason this is a good thing is because a delegate type may have a lot more meaning that just it's technical components would imply. Like any other data type, when we create delegates for our applications, we usually apply some kind of semantic meaning to those types. We expect, for example, that if we have a ThreadStart delegate, that it's going to be associated with a method that runs when a new thread starts. the delegate's signature is about as simple as you get (no parameters, no return value) but the implication behind the delegate is very important.
Because of that, we generally want the compiler to tell us if we try to use the wrong delegate type in the wrong place. More often than not, that's probably a sign that we are about to do something that may compile, and even run, but is likely to do the wrong thing. That's never something you want from your program.
While all that is true, it's also true that often times you really don't want to assign any semantic meaning to your delegates, or else, the meaning is assigned by some other part of your application. Sometimes you really do just want to pass around an arbitrary piece of code that has to run later. This is very common with functional-style programs or asynchronous programs, where you get things like continuations, callbacks, or user-supplied predicates (look at the various LINQ methods, for example). .NET 3.5 and onward supply a very useful set of completely generic delegates, in the Action and Func family, for this purpose.
Consider the following code:
public class Foo
{
public int Bar { get; set; }
}
public class SomeOtherFoo
{
public int Bar { get; set; }
}
Should I be able to say:
Foo foo = new SomeOtherFoo();
That won't work in C# either. When you have two different types that have the same body/implementation, they are still different types. Two classes with the same properties are still different classes. Two different delegates with the same signature are still different delegates.
The Sort method has already defined the delegate type, and you need to match it. This is very much like it defining a class that it needs to accept as a parameter; you can't just pass in another type with the same properties and methods.
This is what it means for a language to be statically typed. An alternate type system would be to use "Duck Typing" in which the language doesn't apply the constraint that a variable be of a specific type, but rather that it has a specific set of members. In other words, "If it walks like a duck, and quacks like a duck, pretend it's a duck." That is opposed to the style of typing that says, "It must be a duck, period, even if it knows how to walk and quack."

C# generics: any way to refer to the generic parameter types as a collection?

I need to write a bunch of methods that take 1..N generic type parameters, eg:
int Foo<T1>();
int Foo<T1,T2>();
int Foo<T1,T2,T3>();
...
int Foo<T1,T2,T3...TN>();
Inside Foo() I would like to do something for each type, eg
int Foo<T1,T2,T3>() {
this.data = new byte[3]; // allocate 1 array slot per type
}
Is there any way to parameterize this so that I am not editing every variation of Foo(), something analogous to:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
}
Ideally, I'd also like to be able to get an array or collection of the types as well:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
// can do this
Type [] types = new Type[] { T1, T2, T3 };
// but would rather do this
Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS;
}
You can read the current generic parameters and their number from the MethodInfo.GetGenericArguments array.
You can retrieve the MethodInfo for your current method by using the MethodBase.GetCurrentMethod method.
Note that you will still need to supply several generic overloads of your method with different numbers of generic parameters, as C# and the CLI do not support variadic generic parameter lists.
So, your code sample for the method with three generic parameters could be written like this:
int Foo<T1,T2,T3>() {
MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
Type[] types = mInfo.GetGenericArguments();
this.data = new byte[types.Length];
}
1) You can get the number of template arguments via reflection: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx . This way, you can have common implementation for each Foo. In each Foo you can just call:
FooImpl();
The only difference (regarding the "GetCurrentMethod") is that you'll need to get method info of the previous method:
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
2) You could generate all Foo versions at runtime - all would share the same implementation of calling FooImpl only. Some details on generating methods at runtime: Creating a function dynamically at run-time and here: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx
The .NET framework regards a generic class or method with N type parameters as having a different name from one having more or fewer. It would probably be possible without a huge change to the framework to arrange things so that calling a function
foo<T>(autogeneric ref T it)
as:
foo(1, "George", 5.7);
would get translated as to:
struct foo99 {public int p1; public string p2; public double p3};
...
foo99 temp99;
temp99.p1 = 1;
temp99.p2 = "George";
temp99.p3 = 5.7;
foo1(ref temp);
That would allow a generic method to efficiently accept an arbitrary number of parameters. Being able to pass such anonymous structure by ref might not seem terribly useful, but it could be very powerful when combined with lambdas.
Normally, closing over local variables in a lambda expression would require hoisting the local variables to a heap object and building a delegate which targets that heap object. If one could use the above style, one could instead of creating a persistent closure object and a delegate and passing the delegate, simply hoist the appropriate variables to a structure and pass a byref to it along with a static delegate. This would only work in cases where the called routine wouldn't have to persist the passed-in closure, but on the flip side the caller would know that the called routine wouldn't be persisting the closure. Further, while no .NET languages would support such a thing and some framework changes might be required to allow code which did this to be volatile, passing by reference a structure some of whose members were also byrefs could make it possible for a lambda to access the enclosing procedure's ref parameters--something which is presently not possible (since there's no guarantee the created delegate wouldn't outlive the scope where it was created). Structures die when the scope they're in dies, so the problem wouldn't have to exist with them.
I wish .NET languages had a convenient way of expressing these concepts. The fact that closures can cause variables' lifetimes to be arbitrarily persisted means that code which has ever used a variable in a closure must assume that outside code could change it at any time. A struct-based approach wouldn't have that issue.
No.
You can not use the Type parameter as you want. But you could use something like Tuple. It allows you to Wrap generics. But you can not use the TypeParamter itself.

Can you reference a non-static method in a static context?

Use of delegates follows the same rules as calling methods - you can only refer to a method via a delegate if you are allowed to call that method explicitly, which means you cannot reference a non-static method from a static method, even if you don't actually call it. Is there a way around that?
Here is some code used in performing the Bowling Kata, with my ideal lines of code shown in comments. I was forced to go through a static call (and anonymous static method declarations) to make the Frame Class code declarative to my liking:
public int FrameScore()
{
return scorer[FrameType()](this);
// I would like it to be
// return this.scorer[FrameType()]();
}
static Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>> scorer =
new Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>>()
{
{LinkedFrame.FrameTypeEnum.Strike, frame => frame.StrikeScore()},
{LinkedFrame.FrameTypeEnum.Spare, frame => frame.SpareScore()},
{LinkedFrame.FrameTypeEnum.Regular, frame => frame.RegularScore()}
// I would like an element to be
// {LinkedFrame.FrameTypeEnum.Strike, StrikeScore}
};
private int RegularScore()
{
return this.Sum;
}
private int SpareScore()
{
...
}
private int StrikeScore()
{
...
}
So in some contexts it would make sense to reason about non-static methods in a static context. Is there a way to do this?
Maybe open instance delegates will help?
According to MSDN: Delegate Class:
When a delegate represents an instance method closed over its first argument (the most common case), the delegate stores a reference to the method's entry point and a reference to an object, called the target, which is of a type assignable to the type that defined the method. When a delegate represents an open instance method, it stores a reference to the method's entry point. The delegate signature must include the hidden this parameter in its formal parameter list; in this case, the delegate does not have a reference to a target object, and a target object must be supplied when the delegate is invoked.
What it comes down to, is that you can sneakily convert an instance method to a static method with an explicit this parameter. You can see how it's done here: Simon Cooper: Introduction to open instance delegates
An instance method always requires an instance to be invoked with.
If you want to invoke an instance method through a delegate, you have two options:
The delegate captures the instance in some way.
You need to pass the instance to the delegate.
You seem to want to have a delegate that does not capture an instance and does not require an instance to be passed. That's not possible in C#.

What is the difference between Func<string,string> and delegate?

I see delegates in two forms:
A. Func<string, string> convertMethod = lambda
B. public delegate string convertMethod(string value);
I'm uncertain of what actually the difference between these two are. Are they both delegates? I believe the first one would use a lambda and the second would have to have a method to actually perform the work. I may be confused too.
First of all, your two examples are doing two totally separate things. The first is declaring a generic delegate variable and assigning a value to it, the second is just defining a delegate type. Your example, more completely, would be:
public static class Program
{
// you can define your own delegate for a nice meaningful name, but the
// generic delegates (Func, Action, Predicate) are all defined already
public delegate string ConvertedMethod(string value);
public static void Main()
{
// both work fine for taking methods, lambdas, etc.
Func<string, string> convertedMethod = s => s + ", Hello!";
ConvertedMethod convertedMethod2 = s => s + ", Hello!";
}
}
But more to the point, both Func<string,string> and delegate string convertMethod(string) would be capable of holding the same method definitions whether they be methods, anonymous methods, or lambda expressions.
As for which you should use, depends on the situation. If you want your delegate to be defined more by what it takes and returns, then the generic delegates are perfect. If you want the delegate to have some special name that gives more definition of what that delegate should do (beyond simple Action, Predicate, etc) then creating your own delegate is always an option.
The code sample you have is confusing things a bit so let me try and clear it up. The following 2 items are delegate declarations. These are easy to spot because they will always contain the delegate keyword
public delegate TReturn Func<TArg, TReturn>(Targ value);
public delegate string convertMethod(string value);
This line of code is assigning a value to a local which is typed to a delegate
Func<string, string> local = lambda;
The above code is not limited to using just lambdas though. The value could also be a compatible method group or another delegate value.
One other item to note is that even though Func<string, string> and convertMethod are both delegates with identical signatures their values are not convertible to each other. For example the following is illegal
Func<string, string> local1 = ...;
convertMethod local2 = local1; // Error!!!
From MSDN,
In versions of C# before 2.0, the only way to declare a delegate was
to use named methods. C# 2.0 introduced anonymous methods and in C#
3.0 and later, lambda expressions supersede anonymous methods as the
preferred way to write inline code.
and
There is one case in which an anonymous method provides functionality
not found in lambda expressions. Anonymous methods enable you to omit
the parameter list. This means that an anonymous method can be
converted to delegates with a variety of signatures.
You may also be interested in this SO answer on delegate keyword vs lambda expression.
Additionally, MSDN has a good article on Lambda Expressions:
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
In the previous example, notice that the delegate signature has one
implicitly-typed input parameter of type int, and returns an int. The
lambda expression can be converted to a delegate of that type because
it also has one input parameter (x) and a return value that the
compiler can implicitly convert to type int. (Type inference is
discussed in more detail in the following sections.) When the delegate
is invoked by using an input parameter of 5, it returns a result of
25.
A initializes an instance of a delegate (that can be called immediately). It's a variable of type Func< string, string >.
B specifies the definition of a delegate (its signature). It can be used to later define variables of type convertMethod.

Covariant instance types on open instance delegates

I'm trying to create open instance delegates for methods that share a common signature, but are defined on many different and unrelated types. These methods are tagged with a custom attribute, and at runtime I lookup all the methods tagged with this attribute in order to construct delegates out of their MethodInfos. For instance, given the delegate:
delegate void OpenActionDelegate(object instance, float someParam);
I would like to match the methods:
void Foo.SomeAction(float someParam);
void Bar.SomeOtherAction(float someParam);
Where Foo and Bar are completely unrelated classes. Armed with the MethodInfo for either method, I'd like to ultimately be able to get an open delegate like so:
MethodInfo fm = typeof(Foo).GetMethod("SomeAction", BindingFlags.Public | BindingFlags.Instance);
MethodInfo bm = typeof(Bar).GetMethod("SomeOtherAction", BindingFlags.Public | BindingFlags.Instance);
OpenActionDelegate fd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), fm);
OpenActionDelegate bd = (OpenActionDelegate)Delegate.CreateDelegate(typeof(OpenActionDelegate), bm);
The problem I'm running into is the type of the explicit instance specification in the delegate. Since these methods don't have a guaranteed base type they'll be defined on, I've tried just setting object. But trying to bind the MethodInfo fails, presumably because parameter types are not covariant when binding delegates. Switching the delegate signature to have the instance param be of type Foo or Bar works for binding the corresponding MethodInfo.
I don't believe it's actually possible to bind an open delegate like this, because then the explicit instance param wouldn't be of the appropriate type on which to call the method. What bothers me is it is possible to bind a closed delegate to a MethodInfo of any declaring type, since that doesn't include the troublesome instance type. Case in point, I can bind closed delegates to null instances, and then use GetField("_target").SetValue(del, instance) on the delegates just before invoking them. But that's kind of hackish.
Now, in case there are alternative solutions, the reason I'm looking to do this is to avoid heap allocation and value type boxing when directly invoking the MethodInfos, i.e.:
someActionInfo.Invoke(instance, new object[] { someParam });
This causes boxing of the float type, and the object[] array is allocated on the heap, both slowly generating heap garbage for an otherwise throwaway invocation.
Parameter types, including the implicit "this" parameter, clearly cannot be covariant and still be typesafe. Forget about instance methods for a moment and just think about static methods. If you have
static void Foo(Mammal m) {}
then you can't assign that to a delegate that takes an Animal, because the caller of that delegate could pass in a Jellyfish. You can assign it to a delegate that takes a Giraffe though, because then the caller can only pass in Giraffes, and giraffes are mammals.
In short, to be typesafe you need contravariance, not covariance on parameters.
C# does support that in a couple of ways. First off, in C# 4 you can do this:
Action<Mammal> aa = m=>m.GrowHair();
Action<Giraffe> ag = aa;
That is, conversions on the generic action type are contravariant when the varying type parameters are reference types.
Second, in C# 2 and above you can do this:
Action<Giraffe> aa = myMammal.GrowHair;
That is, method group conversions to delegate are contravariant in the parameter types of the method.
But the kind of covariance you want is not typesafe and therefore not supported.
Your problem is that you want to create a delegate that does two things - a cast and a method call. If it were possible, you'd do it with generics:
public OpenActionDelegate GetDelegate<T>(MethodInfo method) {
return (object instance, float someParam) => {
((T)instance).method(someParam);
};
}
Unfortunately the first can only be done with generics, and the second only with reflection - so you can't combine the two!
However, if you create the delegates once and use them many times, as it seems is the case, it might be efficient to dynamically compile an expression that does it. The beauty of Expression<T> is that you can do anything with it - you're basically metaprogramming.
public static OpenActionDelegate GetOpenActionDelegate(Type type, string methodName) {
MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
ParameterExpression instance = Expression.Parameter(typeof(object));
ParameterExpression someParam = Expression.Parameter(typeof(float));
Expression<OpenActionDelegate> expression = Expression.Lambda<OpenActionDelegate>(
Expression.Call(
Expression.Convert(
instance,
type
),
method,
someParam
),
instance,
someParam
);
return expression.Compile();
}
This method will compile and return an OpenActionDelegate that casts its parameters to type and calls methodName on it. Here's some example usage:
public static void Main() {
var someAction = GetOpenActionDelegate(typeof(Foo), "SomeAction");
var someOtherAction = GetOpenActionDelegate(typeof(Bar), "SomeOtherAction");
Foo foo = new Foo();
someAction(foo, 1);
Bar bar = new Bar();
someOtherAction(bar, 2);
// This will fail with an InvalidCastException
someOtherAction(foo, 2);
Console.ReadKey(true);
}
So as it turns out, the Xbox 360 .NET framework isn't very fond of using reflection to change non-public fields. (Read: It outright refuses to.) I imagine that's to prevent reverse-engineering some sensitive XDK information. In any event, that ruled out the little reflection hack from the question that I had ended up using.
I did, however, piece something together with generic delegates. Replace:
delegate void OpenActionDelegate(object instance, float someParam);
With:
delegate void OpenActionDelegate<T>(T instance, float someParam);
During the initial reflection, I have the MethodInfo for all the relevant types, meaning I can use reflection and MakeGenericType to create type-safe delegates for the actions without having to create them all by hand. The resulting open delegates bind flawlessly, so my delegate list is populated. However, these are stored as plain Delegates, meaning I couldn't access them safely without using a prohibitive DynamicInvoke.
As it turns out, the action invocation method originally passed its instances as objects, it turns out that I can, in fact, make it generic in order to get the proper type for the generic delegates, and cast the Delegates back to an OpenActionDelegate<Foo>, for instance:
internal static void CallAction<T>(int actionID, T instance, float param)
{
OpenActionDelegate<T> d = (OpenActionDelegate<T>)_delegateMap[actionID];
}
So this way, I dodge the covariance issue altogether, get the speed of a direct delegate call and avoid boxing. The only inconvenient is that this approach won't work with inheritance, since delegates are bound to their declaring type. I'll have to considerably improve the reflection process if I ever need to support inheritance.
Because delegates predate generics, they can't do all the things that generic interfaces can. I'm not quite clear what you're trying to do, but it seems like something that interfaces could do without need for Reflection, if you can add appropriate interfaces to the classes whose methods you want to call. For example, if all the methods you're interested in are in IWoozable and take a float parameter, then you could define an interface IWoozer with method void Woozle(IWoozable target, float someParam); One IWoozer implementation could be
void Woozle(IWoozable target, float someParam)
{
target.Method1(someParam);
}
Another could be similar but use Method2, etc. One could easily put in arbitrary code without need for delegates, and have the choice of action be independent of the choice of target.
Another thing one can do with generic interfaces which cannot be done with delegates is include open generic methods. For example, one could have an interface
interface IActUpon<T>
{
void Act(ref T target);
void ActWithParam<PT1>(ref T target, ref PT param);
}
A class which holds a T can then expose it to a method like the above:
void ActUponMyThing<ActorType>(ref ActorType Actor) where ActorType:IActUpon<T>
{
Actor.Act(ref T myThing);
}
void ActUponMyThingWithParam<ActorType,PT>(ref IActUpon<PT> Actor, ref PT param)
where ActorType:IActUpon<T>
{
Actor.ActWithParam(ref T myThing, ref PT param);
}
The use of constrained generic types for the interfaces makes it possible in some cases to use structs and avoid boxing, something which would not be possible with delegates. Further, it's possible for open generic methods to apply multiple constraints to their generic type parameters, and call generic methods which likewise have multiple constraints, even if the classes which implement the constraints do not share a common base type.

Categories

Resources