Using a List<> to store methods in C# Unity3D? - c#

I'm attempting to store a List of methods inside a List<dynamic>to create a part of my Quest system. I've never used Lists and I don't exactly know what the dynamickeyword does, so I'm having problems understanding.
To begin with, I've created a test function, and I'm trying to store it inside the List<dynamic>, and then output what the Test function returns through the console (Debug.Log()). Here's the code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Quests : MonoBehaviour
{
public List<dynamic> activeQuests = new List<dynamic>();
void Start()
{
activeQuests.Add(Test());
Debug.Log(activeQuests[0]);
}
public bool Test()
{
return true;
}
}
A red line appears under Debug.Log(activeQuests[0]); and the error message shown as below -
"One or more types required to compile a dynamic expression cannot be
found. Are you missing a reference?"
How do I make this work?
Edit: I'm also looking for a way to add overload methods to each of these functions with parameters.

If the method are always parameter less I suggest to use this:
public List<System.Action> activeQuests = new List<System.Action>();
// usage
activeQuests.Add(Test)
Maybe a return value is needed. Then you should go with any Systen.Func<T ...> delegate.
public List<System.Func<bool>> activeQuests = new List<System.Func<bool>>();
// usage
activeQuests.Add(Test)

One solution is to not use dynamic. If you can make your quest methods conform to the same signature, like bool Test() as you have there, then you can store it using strong typing just fine.
Func<bool> represents a delegate that takes no parameters and returns a bool. So make a List<Func<bool>> and you'll have a list of functions that take no parameters and return a bool.
A mistake you're making is activeQuests.Add(Test());. This calls Test then adds the return value to activeQuests, but you want to add Test itself to activeQuests. Get rid of those () so you don't call the function.
Edit: If you want to pass parameters to your functions, check out the other versions of Func<>. If you add more types, you start adding parameters. For example, Func<int, bool> is a delegate that takes one int parameter and returns a bool.
If all your delegates are in a single list, it makes sense to give them all the same signature. This way you can call any of them with strong typing. For example, you could call each function in activeQuests like this:
foreach (Func<int, bool> questFunction in activeQuests)
{
questFunction(5);
}
Similarly, check out Action and Action<...>. When you add more generic parameters, you're adding parameters the delegate takes. But Action delegates don't have return values, which might fit what you really want better. Everything else works exactly the same.

putting () parenthesys after a method name calls the method, it does not reference the method.
So with this logic: activeQuests.Add(Test()); is actually calling Test() and looking for a return value to pass into activeQuests. Instead, you want to send a reference to the Test() method into activeQuests, so you have to pass it without the parenthesys, i.e. activeQuests.Add(Test);. But activeQuests needs to be a list of methods (Action<...> or Func<...>), not a list of dynamic.

Related

C# polymorphism with generic type and list

Maybe my question is simple or just stupid but I have following problem:
I have 2 polymorphic methods:
public void Index<T>(string alias, IEnumerable<T> items) where T : class
{
var result = Client.IndexMany(items, alias);
ExceptionHandling(result);
}
public void Index<T>(string alias, T item) where T : class
{
var result = Client.Index(item, x => x.Index(alias));
ExceptionHandling(result);
}
When I'm now trying to call the method which is getting a List with following command:
ClientService.Index(Alias, items.ToList());
Always the method Index<T>(string alias, T item)is getting called. How can I change it that Lists call the first Method and single objects call the second Method?
I have an alternative solution!
You can use parameter names to differentiate the overloads!
You see, the first overload's second parameter is called items, whereas the second overload's second parameter is called item. Therefore, if you want to call the first overload, you just need:
ClientService.Index(Alias, items: items.ToList());
If you want the second instead, you can call:
ClientService.Index(Alias, item: items.ToList());
See the difference?
Clean and tidy! Tested on chsarppad: http://csharppad.com/gist/0d7f71c66079fefa680ea3f6afb2ed63
This is the problem with having the same name for a method (overloading) where the two overloads clearly do different things - you have a hint to the solution; elsewhere you have named the downstream methods Index and IndexMany.
Your two options are
Name the methods differently, and appropriately
Explicitly cast your list to an IEnumerable<T> using AsEnumerable() extension method.
You could specify the generic argument type e.g.
ClientService.Index<Item>(Alias, items.ToList());

C# Reflection with generics

I have been searching for this for some time but not gotten anywhere. I want to do the following:
Given a type say Dictionary<string,MyClass> and say its method ContainsKey(string) - at run time
I want to be able to extract out the 'Generic signature' of this method. That is I want to get
Boolean Dictionary<TKey,TValue>.ContainsKey(TKey) ( and not Boolean ContainsKey(string) )
I know that this is possible by doing the following
var untyped_methods = typeof(DictObject).GetGenericTypeDefition().GetMethods();
// and extract the method info corresponding to ContainsKey
However is is possible to get this information directly from the methods reflected from the
actual type and not from the Generic types ? Meaning Can I get the generic definition
from methods that have been obtained as follows :
var actual_typed_methods = typeof(DictObject).GetMethods()
In essence is it possible to get the "un-typed" method signatures from MethodInfo objects returned in the second snippet above directly (not via comparing the lists and figuring out)
Thanks
EDIT: Maybe this did what you wanted. Not sure if you were actually looking to Invoke or not.
If Invoking, then no (see below). If you just want the definition, then you can use typeof(Dictionary<,>) to get the raw generic definitions.
Unfortunately, no if you are wanting to Invoke.
Demonstration of why:
void Main()
{
var genericDictionaryType = typeof(Dictionary<,>);
var method = genericDictionaryType.GetMethod("ContainsKey");
var dict = new Dictionary<string, string>();
dict.Add("foo", "bar");
Console.WriteLine("{0}", method.Invoke(dict, new[] { "foo" }));
}
Yields the following error:
Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
Sounds simple enough to fix. Just call method.MakeGenericMethod(typeof(string)); to get the actual typed MethodInfo object.
Unfortunately again, you cannot.
Boolean ContainsKey(TKey) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.
Reason for this is because the method defined as bool ContainsKey(TKey) instead of bool ContainsKey<TKey>(TKey).
You will need to get the ContainsKey method from the correct Dictionary<TK,TV> signature in order to use it.

How to Dynamically Create Method from String for Lambda Expression

My ultimate goal is to create a function that will dynamically pass method names to classes in the Hangfire library.
For example, here is the non-dynamic code which works:
RecurringJob.AddOrUpdate(() => myFunction(), Cron.Hourly)
The type of the first argument for AddOrUpdate is Expression<Action>. My first step was to use reflection to dynamically insert the function name:
Type thisControllerType = this.GetType();
MethodInfo method = thisControllerType.GetMethod(methodName); //methodName passed as string parameter
RecurringJob.AddOrUpdate(() => method.Invoke(this, null), Cron.Hourly);
When I check the Hangfire dashboard, it seems that this expression is being evaluated as MethodBase.Invoke. So I need help passing in the method name dynamically.
That may be enough info to answer my question, but another path I have taken is trying to generate the entire expression for the argument.
RecurringJob.AddOrUpdate(CreateCallExpression(method), Cron.Hourly);
public Expression<Action> CreateCallExpression(MethodInfo method)
{
//trying to pass in zero argument parameter, not sure if this syntax is correct
var parameter = System.Linq.Expressions.Expression.Parameter(typeof (Array));
return System.Linq.Expressions.Expression.Lambda<Action>(System.Linq.Expressions.Expression.Call(method, parameter));
}
In this case I am getting the exception {"Static method requires null instance, non-static method requires non-null instance.\r\nParameter name: method"}. I am working on that, but not sure if this is the road I should be going down. I have been working on this all day, so I was hoping someone might be able to help me speed up my learning.
Your second instance will work in creating a pointer to your specified method, but to solve your static issue you just need to modify the following line in one of 2 ways. First you can complete the static reference by declaring the method you seek to be static and modifying this line of code:
System.Linq.Expressions.Expression.Call(method, parameter);
You would have to provide a null parameter for the call method because if you are searching for a static method, then the compiler will know exactly what method signature you desire, because there will only exist 1. The line of code would be updated to:
System.Linq.Expressions.Expression.Call(null, method, parameter);
The second approach is to define the class or "instance" that correlates to the method so that the compiler knows what class to search against for the method signature. You would have to modify your code like this:
var myInstance = Expression.Parameter(typeof(MyClass), "inst");
System.Linq.Expressions.Expression.Call(myInstance, method, parameter)
I recommend looking at the documentation for Call so that you know exactly how the pointer is being created.

Passing methods as parameter vs calling methods directly

I have seen methods passed as parameters in some examples. If I can call one method from another method, why should I pass method as a parameter? What is the purpose behind this design?
Calling one method from another
Passing method as parameter using delegate or Action
Passing in a method as a parameter can be used to prevent dependencies and coupling. Let's take a look at how this can be used for the Strategy pattern:
Let's say we have a method PrintReport, which prints a given list of items, which might be sorted by Name or by Type, based on a parameter. This is the naive approach:
public void PrintReport (List<Item> data, SortOrder sortBy)
{
List<Item> sortedItems;
switch (sortBy)
{
case SortOrder.Name: sortedItems = SortByName(data); break;
case SortOrder.Type: sortedItems = SortByType(data); break;
}
Print(sortedItems);
}
It's simple but it works. But what happens when we want to add a new sort order? We need to update the SortOrder enum, go into PrintReport and add a new case and call the new SortByWhatever method.
But if we passed in a method as a parameter, our PrintReport can be simpler and not care about the sort implementation:
public void PrintReport (List<Item> data, Func<List<Item>, List<Item>> sorter)
{
List<Item> sortedItems = sorter(data);
Print(sortedItems);
}
Now the sorting function can be defined anyway, possibly even in a different assembly that PrintReport isn't even aware of. It can be a lambda function or an anonymous method defined ad-hoc. But in all cases, our method will receive the delegate, use it to sort, and then print the report.
Here's a usage example. At first it looks like we merely moved the switch/case outside of the function, which is important enough since it allows different callers to have different logic. But watch for the third case.
public void HandleData()
{
switch (ReportItemOrder)
{
case SortOrder.Name: PrintReport(data, SortByName); break;
case SortOrder.Type: PrintReport(data, SortByType); break;
case SortOrder.Whatever:
Func<List<Item>, List<Item>> customSort = (items) => /* do something */;
PrintReport(data, customSort);
}
}
Delegates are commonly used to decouple classes and interfaces from each other.
Here's a specific example. Suppose you had a UI class that was responsible for drawing a calendar, but you didn't want it to know exactly how to format the DateTime values into string.
You could define the class something like this:
public sealed class MyCalendarDrawer
{
private readonly Func<DateTime, string> _dateFormatter;
public MyCalendarDrawer(Func<DateTime, string> dateFormatter)
{
_dateFormatter = dateFormatter;
}
public void Draw()
{
// Do some work that involves displaying dates...
DateTime date = DateTime.Now;
string dateString = _dateFormatter(date);
// Display dateString somehow.
}
}
That way, MyCalendarDrawer doesn't need to know how to format the dates - it is told how to do it by being passed a delegate Func<DateTime, string> that it can call to do so.
Treating functions as first class types has its advantages. It gives you functional programming possibilities.
Take the classic case of "Event Handling" for example, you will certainly send a function pointer to another function as a call-back on occurance of an event.
Similarly, here is another hypothetical example
private void CallMeBack(out int type, Func<int> action)
{
type = action();
}
Now I can supply any function to this, like CallMeBack(a, ()=>return 1); and CallMeBack(a, ()=>return 2);
You should read about Delegates.
As example, delegates are useful to define a dynamic callback on a given method completion.
Pseudo-code example:
doSomething(); //your code
updateInterface(continueDoingSomething); //a generic method, passing a delegate
...
doAnythingElse();
updateInterface(continueDoingAnythingElse);
In this example, you could define a generic method "updateInterface" which, as a callback, calls a dynamic method passed in as a delegate.
If not using delegates, you would have to implement two (or more) different methods:
void updateInterfaceAndContinueDoingSomething(){}
void updateInterfaceAndContinueDoingAnythingElse(){}
Truth is, every single example where functions are passed to other functions can be expressed in term of objects implementing a given interface passed to functions.
In other words, there are no obvious reasons delegates are better than interfaces. Upcoming lambdas in Java are an example than you don't really need to be able to pass a function to another function to be able to have a concise syntax.
In yet another words, the ability to pass a function to another function is just a tool in your programmer's toolkit just as passing objectd to functions is. And while this is arguable which is better, one can have a language that doesn't support passing functions to functions at all - Java - and still be able to have the same expressiveness.

C# - Is it possible to get the owner type of a method from an Action?

I have a class that implements an Interface with some methods.
I also have method with an Action parameter where I pass the Interface method.
Is it possible to get the type of the owner that has the method?
EDIT
This is the wrapper:
private void Wrapper (params Action[] actions)
{
var action = actions.FirstOrDefault();
var type = action.Method.DeclaringType.Name;
}
private void test()
{
Wrapper(()=> _GC.ChargeCancellation(""));
}
For demonstration purpose I don't iterate through the collection.
I want the type of _GC.
Actually, I should've spotted this to begin with but since Jon didn't either I'm not feeling too bad about it :)
The code you have to begin with in your question does not compile:
Wrapper(() => TestClass.Hello);
This is not complete code. You either have to have:
Wrapper(TestClass.Hello);
^
|
+-- notice the missing () => here
or:
Wrapper(() => TestClass.Hello());
^
|
+-- notice the added parenthesis here
And now that you have edited your question, it is clear you have the second form.
There's a subtle difference between the two. Subtle to us, but important to the compiler:
Wrapper(TestClass.Hello);
^------+------^
|
+-- This is a method group
Wrapper(() => TestClass.Hello());
^------+--------^
|
+-- This is a method call
A method group is a reference to a method (or its overloads), a method call is executable code.
The difference to the compiler is that in the first piece of code, the compiler will wrap up the method group into an action, basically compile it like this:
Wrapper(new Action(TestClass.Hello));
and thus, you're passing that method to the Wrapper method, inside an Action delegate.
However, the second form is handled altogether differently. The compiler now produces a new method to contain your code, and then passes the new method to the Wrapper method instead of the code you had.
Thus, your code actually looks like this:
public static void Main()
{
Wrapper(new Action(TempMethod1));
}
private static void TempMethod1()
{
TestClass.Hello();
}
And that's why you're seeing the form class as the owner of the method, because that's what it is.
The reason I asked in a comment whether you were taking a delegate or an expression is that my brain was working at half speed. It detected something odd, but not the whole picture.
If you want to pass code like this to a method, and work with it, you have two choices:
For a delegate, work with reflection, decompile the code and analyze it, find the method call and figure out which class it is made on
For an expression, analyze the pieces of the expression (this requires C# 3 or above)
Since neither is trivial I'm not going to post any code here, suffice to say that what you're asking warrants a new question. Of the two, I suggest you go with the expression way if you can.
EDIT: I misread the example, and thought it was using a method group conversion. You can certainly get the method in the delegate itself:
public void Wrapper(Action action)
{
MethodInfo method = action.Method;
Type type = method.DeclaringType; // TestClass
string name = method.Name; // Hello
}
I'm not sure off the top of my head which method will be used if you pass in a delegate instance with multiple actions... but it shouldn't be a problem in this case.
Doh - I misread the question. When you use a lambda expression, that's going to build an extra method in the calling class - and that is the method which contains the reference to _GC.
If you don't want this behaviour, you should change Wrapper to accept params Expression<Action>[] actions - you can then examine the expression trees appropriately and find out the calls that way. It's a bit fiddly sometimes, but it's doable. Look at the Body of the expression tree, which will represent the method call. Note that if you still want to execute the actions, you can call Compile on the expression tree to obtain a delegate.

Categories

Resources