My goal is to be able to pass in a a method as a parameter just like a call back in javascript, But without specifying it's return value, or its function signature.
For example in javascript I could do:
function test(fn()){
fn();
}
fn() in JavaScript can be interpreted to any function type:
function [return value] test(){}
function [void] test(){}
function [...] (arg1,arg2...){}
(function arguments overloading is possible...)
C# isn't offering me much with "Action" and "Func".
In C# I can create a delegate and then specify which type of a delegate it is:
Action: a delegate to a function that returns void, all functions that the Action will point to, have to contain the same exact signature (not cool...)
Func: a delegate to a function that returns a value, all functions that the Func will point to, have to contain the same exact signature (not cool...)
Using an Object will bring me to an expensive boxing/unboxing story, which I would like to avoid.
C# experts, talk to me..
You call it "not cool", I call it "type safe"....
One solution might be the way you call the method. When this is the method you want to call:
public void Test(Action fn)
{
fn();
}
And this is the one you want to pass:
public string MethodWithReturnType()
{
return "Hello World!";
}
Then you can call Test with MethodWithReturnType by using a lambda:
Test(() => MethodWithReturnType());
Your only real option is object function(object[]){} but as you say there are huge issues with interpreting the object actual type. C# is a strongly typed language unlike javascript and so the capabilities that you want are just not possible, and if they are then they shouldn't be used because you'll lose all of the advantages of using a strongly typed language in the first place.
Related
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.
I have a piece of code like this:
GoAsync(() => GetPackagesExecute(serviceType));
how to understand this code?, what means the braces without name method?
It is difficult to tell you exactly what those methods do, because they aren't "standard" methods...
The GoAsync for example could have various signatures:
void GoAsync(Action action);
void GoAsync(Func<FooType> func);
or even more complex, like:
void GoAsync(Expression<Action> action);
void GoAsync(Expression<Func<FooType>> func);
Let's say that the GoAsync has a signature like:
void GoAsync(Action action);
Now, GoAsync accepts as a parameter a delegate, that is a reference to a function. This function mustn't have any parameter and mustn't return anything (if we had chosen the second signature, void GoAsync(Func<FooType> func);, then the function would have returned a FooType object). GoAsync then can execute that function reference and do some operations on it. Note that GoAsync could even not execute that delegate.
() => GetPackagesExecute(serviceType)
This creates an anonymous function that doesn't have any parameter and that has as the body GetPackagesExecute(serviceType), so in its body it simply executes the GetPackagesExecute with a parameter serviceType (that is probably a local variable or a field/property).
In functional language this is called currying (creating a function that calls another function, the called function has more arguments than the created function). In this case the anonymous function has 0 arguments, GetPackagesExecute has one argument.
Technically this anonymous function could return the return value of GetPackagesExecute(), so it is equivalent to both:
void AnonymousMethod()
{
GetPackagesExecute(serviceType);
}
and to
FooType AnonymousMethod()
{
return GetPackagesExecute(serviceType);
}
The exact "type" of the anonymous function is selected by the C# compiler based on the signature of GoAsync(). This is called type inference in lambdas.
Now, the
GoAsync(() => GetPackagesExecute(serviceType));
together will:
Create an anonymous function (it is a little more complex than this... there is some C# compiler-magic here, but you can ignore it)
Create a delegate to that anonymous function (this is implicit, and done by the C# compiler)
Call GoAsync passing this delegate to it
The GoAsync will probably do something with the delegate
It is something called a lambda expression. It is a fairly advanced topic but it is a pretty core piece of functionality. It is really hard to explain it all so I have found this link for you to look through.
https://msdn.microsoft.com/en-us/library/bb397687.aspx
It will explain everything however depending on your level of experience it might not make any sense, it should give you a jumping block to move on and investigate it further.
I'm using Lua interface on c# to pass an object I created to lua's function.
It successfully calls the function, but lua is keep throwing an error:
LuaInterface.LuaException: /hook.lua:32: attempt to index local 'objj' (a nil value)
This is the c# code:
public class PerObj
{
public string name;
public PerObj()
{
}
}
PerObj obj = new PerObj();
LuaFunction lf = lua.GetFunction ("item.HookMe");
lf.Call(obj);
And here's the lua code:
function item:HookMe(objj)
objj.name= "lalala"
end
The function is actually being called, but I'm not sure it's not working...
Change the function definition to:
function item.HookMe(objj)
objj.name= "lalala"
end
The colon in the original definition means that the function has also the self parameter. Those function are called like this: object:HookMe(). But you want to call it directly, so the colon is not applicable.
Edit:
If you want to keep the function defininition and retain self, call it like this:
lf.Call(null, obj);
To call it passing also the self object:
lf.Call(lua["item"], obj);
It seems like the problem is the design of the Lua method (but it really depends on the intent):
Instead of
function item:HookMe(objj)
-- self not used
objj.name= "lalala"
end
This would work better in the given example:
function item:HookMe()
self.name= "lalala"
end
The reason (as well discussed in other answers) is that declaring a function with the method syntax (:) adds an implied first formal parameter self. The caller can pass anything as the first actual argument but the contract is usually to pass the parent table of the function so it can access its sibling fields.
In this case, name seems to be a sibling of HookMe so the method shouldn't be operating on an arbitrary table passed as objj but instead on self.
I have two overloaded methods like below
public class TestClass
{
public void LoadTest(object param)
{
Console.WriteLine("Loading object...");
}
public void LoadTest(string param)
{
Console.WriteLine("Loading string...");
}
}
After calling this method like below it will show the output as Loading string... Please explain how .net handle this scenario?
class Program
{
static void Main(string[] args)
{
var obj=new TestClass();
obj.LoadTest(null);
// obj.LoadType(null);
Console.ReadLine();
}
}
The C# compiler takes the most specific overload possible.
As string is an object, and it can have the value of null, the compiler deems string to be more specific.
null is a valid string.
It will try to match the most specific type and string is more specific than object
Depending on your use you should probably remove the parameter totally in the object overload.
This is just the way C# compiler prioritizes to determine which method is better to call. There is one rule:
If method A has more specific parameter types than method B, then method A is better than method B in overload case.
In your case, apparently string is more specified than object, that is why LoadTest(string param) is called.
You can refer 7.5.3.2 Better function member in C# language specification to get more understanding.
because compiler takes the closest possible specific method that can be accessed (null to string is closer than null to object) that is available. And in this case as both as overload with string is closer, that is why it is called.
This is what MSDN has to say
Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in
all cases:
Given the set of applicable candidate function members, the best function member in that set is located.
If the set contains only one function member, then that function member is the best function member.
Otherwise, the best function member is the one function member that is better than all other function members with respect to the given
argument list, provided that each function member is compared to all
other function members using the rules in Section 7.4.2.2.
If there is not exactly one function member that is better than all other function members, then the function member invocation is
ambiguous and a compile-time error occurs.
delegate IEnumerable<T> GetFromSQLDelegate<T>(...);
public GetFromSQLDelegate myFunctionToCall;
The above does not compile because myFunctionToCall does not specify a type. I'm trying to "store" a generic delegate such that I can invoke it later as a regular generic function:
// ... somewhere in another code base ...
return MyObject.myFunctionToCall<string>(...);
C# complains because I'm not specifying a concrete type on the delegate storage property. Is there a (good) way to "store" a delegate capable of invoking a generic function without implementing various concrete type delegate scenarios?
You can store the value as System.Delegate, make it private, and define a function GetDelegate<T> that casts your stored delegate to the appropriate type:
private Delegate storedDelegate;
public myFunctionToCall<T> GetDelegate<T>() {
return (myFunctionToCall<T>)storedDelegate;
}
You can then call it like this:
return MyObject.GetDelegate<string>()(...);
There is a little bit of ugliness going on around the ()(...) syntax, but it should probably do the trick.
There are no pieces to your puzzle in C#:
you can't have non-generic variable of generic type with non-specified type
you can't create function that matches such imaginary signature
you can't call function and specify type.
So answer is NO. There are multiple different ways to achieve similar behaviors, so if you specify what your actual goal is someone will come up with an approach.