Use Action<object> as method input - c#

I'm in a case where I would like to have a method that can take other methods as input.
The input method will always have a single object as input, but the objects are different.
This is more or less what i need to be able to do:
public static void takeAnything(Action<object> inputFunc)
{
Console.WriteLine(inputFunc.Method.Name);
}
public static void test1(MyOwnObject input){
// Do stuff with input object
}
public static void test2(MyOtherOwnObject input){
// Do stuff with input object
}
public static void startSystem(){
takeAnything(test1);
takeAnything(test2);
}
Which in this dummy case would write out:
test1
test2
I just cant't get this to work, so any help would be very much appreciated.
EDIT
I do not know if this is possible, maybe it is not, but it is important that the call is just takeAnything(test1), not takeAnything<MyOwnObject>(test1) or anything else.

Make your method generic
public static void TakeAnything<T>(Action<T> inputFunc)
{
Console.WriteLine(inputFunc.Method.Name);
}
Of course, you will be able only to pass methods which have single input argument.
UPDATE: Unfortunately C# cannot infer action generic parameter type from usage, when you are passing method group to method, so only way to use it is specifying generic parameter type manually
takeAnything<MyOwnObject>(test)
For details see question C# 3.0 generic type inference - passing a delegate as a function parameter

Try this, so you can pass dynamic parameters to action:
public static void takeAnything(Expression<Action> inputFunc)
{
var currentMethod = ((MethodCallExpression)inputFunc.Body);
Console.WriteLine(currentMethod.Method.Name);
}
public static void test(MyOwnObject input){
// Do stuff with input object
}
public static void startSystem(){
MyOwnObject yourObject = new MyOwnObject();
takeAnything(() => test(yourObject));
}

Why not change the header of your takeAnything method to:
public static void takeAnything(Action<MyOwnObject> inputFunc)

Related

c# - call a specific method when signatures are the same

I'm not sure exactly how to call this situation, but here it is:
I have 2 methods with different types, but from the "outside" they have the same signature. And when calling the method, I would like to invoke a specific method instead of the other - here is what I have:
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
}
For the compiler, the 2 methods above are different and have different signatures. But when calling:
var myClass = new SomeClass();
myClass.MyMethod("name", "something");
When calling MyMethod in the example, what's being called is MyMethod<T>(string name, T myObj), but what I would actually want to call is the second method. Is there a way to make it call a specific signature?
EDIT:
I found the if I give in one of the methods a different name to the second variable and then calling the method with the variable name as part of the call it does work, as in the following example:
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, string myNewObj)
{
// some code here
}
}
var myClass = new SomeClass();
myClass.MyMethod<AnyOfMyTypes>("name", myNewObj: "something");
While this works, following Jon's response below, does it seem like something that is correct to do? As far as for the method name, I would like to keep it the same, and the other option is to change the signature by adding some dummy boolean variable.
The compiler certainly can't call the second method with that calling code, as it wouldn't know what to infer for T. If you specify a type argument though, it does call the second method:
myClass.MyMethod<string>("name", "something");
While that will work, I would strongly advise you to change the design if you possibly can. Rename one of the methods. I can reasonably call myself a C# expert, but I couldn't predict from inspection whether or not that would work. The overload resolution and type inference details in C# are really complicated, and it's unreasonable to expect every C# developer to know them inside out.
If you can give the methods different names, the code code is likely to be a lot simpler to read.
Following Jon's answer I'd suggest following solution to your problem:
private async Task<Response<T>> MethodForString<T>(string str)
{
// some code...
}
public async Task<Response<T>> Method<T>(T obj)
{
if (typeof(T) == typeof(string))
return MethodForString<T>(obj as string);
// some code...
}
Above is just a sample, but idea is simple: just check type of T and call appropriate method :)
This way, all your method call will remain exactly the same :)
The reason the first method is being called is because you have a generic type of T.
If you pass a string into this then it will hit the first method. It is better design to only have one method. If you want to be able to pass in any type then keep the first method, if you want just a string then keep just the second method. You should only have two methods if both have distinct clear purposes.
This
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, T myObj)
{
// some code here
}
}
Or
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
}
Or
public class SomeClass
{
public async Task<Response<T>> MyMethod<T>(string name, string myObj)
{
// some code here
}
public async Task<Response<T>> MyMethod<T>(string name, int age, string address)
{
// some code here
}
}
Dont put a dummy variable into any of the methods, this will lead to problems debugging and be misleading for other developers.

Restrict Return Type of Generic Delegate Irrespective of Parameters

I'm trying to restrict the return type of a generic delegate without specifying the parameter signature, and I don't know how to do this, or if it is even possible.
How can I do this or is it impossible?
My research has come up dry. Some pseudo-C# code would probably help steer you toward what I'm trying to do:
public class SomeClass< T, U > where T : Delegate // returning U
{
private someDelegate;
public SomeClass( T someDelegate )
{
this.someDelegate = someDelegate;
}
public U Run()
{
return someDelegate.DynamicInvoke();
}
}
... Elsewhere
public delegate string aDelegate();
public static string SayHi()
{
return "Hello!";
}
aDelegate greeter = SayHi;
var something = new SomeClass< aDelegate, string>( greeter );
Console.WriteLine( something.Run() ); // Should write "Hello" to the console.
I know this is a rather contrived pseudo example. I aim for a more involved usage, of course. I'm trying to write a console menu class that would associate a list of given menu options with actions that would fire depending on what option the user chooses. Right now, it just returns the string the user chose from the menu. What I'd like be able to do is return what--if anything--the associated method returns. This could perhaps be returned with the user chosen option string in a tuple... But, I figured this mini-example just cut straight to the technical hurdle I'm experiencing.
Thanks!
.NET already defines a generic delegate that returns the generic argument as it's result, Func<T>. You don't even need to define it.
public class SomeClass<U>
{
private Func<U>;
public SomeClass(Func<U> someDelegate)
{
this.someDelegate = someDelegate;
}
public U Run()
{
return someDelegate();
}
}
There's no real useful reason to allow a user of the type to provide any arbitrary delegate of the same signature. Really I'd advise you to avoid using any delegates in your code other than Func and Action (with various different numbers of generic arguments) whenever possible, as it's just creating a hassle to do so. I would consider it a reasonable restriction on any caller that has a delegate of a different type but the same signature to simply convert it to a Func<T> anyway, it's not like it's even a difficult conversion for them.
If you don't want to use Func<T> (as Servy suggests), e.g. if you have a custom delegate of your own that you want to be passed with type-safety, then perhaps you can make your custom delegate generic with respect to its return type. Then you can do it this way:
public delegate T MyDelegate<T>();
public class Foo<T>
{
private readonly MyDelegate<T> _delegate;
public Foo(MyDelegate<T> handler)
{
_delegate = handler;
}
public T Bar()
{
return _delegate();
}
}

Simple way to make a list of functions with parameters to invoke?

I'm looking for a simple way to create a list of functions with parameters which could be invoked. I almost did it but have some issues with setting the method as one of parameters.
This is my code:
public class PlayerInfo
{
public static PlayerInfo Instance; // singleton
public int Energy;
public int MaxEnergy;
public List<KeyValuePair<DateTime, cronTab>> cron;
//some update event for instance every frame of game
void Update() {
var keys = cron;
for (int k=0;k<keys.Count;k++) {
if (keys[k].Key.CompareTo(System.DateTime.Now) < 0 )
{
keys[k].Value.function.Invoke(keys[k].Value.parameter);
cron.RemoveAt(k);
}
}
}
public static void addEnergy(DateTime date)
{
if (PlayerInfo.Instance.Energy < PlayerInfo.Instance.MaxEnergy)
PlayerInfo.Instance.Energy++;
date = date.AddSeconds (10);
PlayerInfo.Instance.cron.Add (new KeyValuePair<DateTime, cronTab>(date, new cronTab(){type = CronType.energy, function = (Action<System.Object>)PlayerInfo.addEnergy, parameter = date}));
}
}
public class cronTab
{
public CronType type;
public System.Object parameter;
public Action<System.Object> function;
}
public enum CronType
{
energy,
mail
}
The problem is that A method or delegate 'PlayerInfo.addEnergy(System.DateTime)' parameters do not match delegate 'System.Action<object>(object)' parameters and I Cannot convert method group 'addEnergy' to non-delegate type 'System.Action<object>'. Do you have any ideas how could I possibly fix it?
Everything becomes way easier when you only use the delegate Action here. Don't have a class that keeps track of the parameter to send, don't try to handle a different number or types of parameters. Trying to do so is a huge mess that, by necessity, removes all static type safety.
Instead close over whatever parameters you need when creating the delegate to transform the method from whatever it was into an Action.
public class CronTab
{
public CronType type;
public Action action;
}
public static void addEnergy(DateTime date)
{
if (PlayerInfo.Instance.Energy < PlayerInfo.Instance.MaxEnergy)
PlayerInfo.Instance.Energy++;
date = date.AddSeconds(10);
PlayerInfo.Instance.cron.Add(
new KeyValuePair<DateTime, CronTab>(
date,
new CronTab()
{
type = CronType.energy,
action = () => PlayerInfo.addEnergy(date),
}));
}
Use this:
function = ((obj) => PlayerInfo.addEnergy((DateTime)obj))
It didn't work before because your delegate stated that it takes an object but the function you were trying to set it to (addEnergy) takes a DateTime.
Please note that System.Object is equivalent to object.
Also, if every cronTab.function takes a DateTime, then you should make it an Action<DateTime>. If you make this change, then you can just have your original code:
function = PlayerInfo.addEnergy
(Note that you wouldn't need a cast to Action<DateTime> here because PlayerInfo.addEnergy is already the correct type.)
Compiler yells at you because your method has incompatible signature than delegate. You either need to change
public Action<System.Object> function;
to
public Action<DateTime> function;
or need to change
public static void addEnergy(DateTime date)
to
public static void addEnergy(object date)
Then remove the explicit delegate cast in the following line
PlayerInfo.Instance.cron.Add (new KeyValuePair<DateTime, cronTab>(date, new cronTab(){type = CronType.energy, function = PlayerInfo.addEnergy, parameter = date}));

How to pass in a lambda and have access to a particular set of methods

I want to have something like:
AStaticClass.MakeCall(commonCmds => commonCmds.MethodOfAParticularClass)
So I want to have a lambda expression as an argument and have the delegate list the available set of methods of a particular class that I can access through intellisense with the lambda function. Then make a call to the passed in method.
i.e. commonCmds => commonCmds. {Lists all the methods of a particular class}
and then I want to have a method that makes that call.
I can't figure it out the proper method signature.
So far I have public void MakeCall(Action cmd) {cmd.invoke;} THis obviously does not work. I tried func, Expression and cannot figure it out.
Thank you so much for the help!
EDIT:
CmdsTwo and CmdsOne Can be static. However I would like to my classes up in this way, since it will make a lot my other work much easier.
public void Main(string []args) {
MyStaticClass.MakeCall(x => x.DoThis);
MyStaticClass.MakeCallTwo(x => x.DoThisTwo);
MyStaticClass.MakeCall(x => x.DoThisThree);
}
public static class MyStaticClass{
public static void MakeCall<???>( ??????)
public static void MakeCallTwo<???>( ??????)
}
public class Cmds{
public void DoThis();
public void DoThisThree();
}
public class CmdsTwo{
public void DoThisTwo();
}
}
The closest i can think of right now is this:
commonCmds => commonCmds.GetType().GetMethods()
This returns you an array of MethodInfo, which describe all methods of the type of commonCmds. You'd have to invoke one of those like this:
object result = someMethodInfo.Invoke(someObjectInstance, new object[] { someParameter });
You can check it
AStaticClass.MakeCall( () => commonCmds.MethodOfAParticularClass)
You need to use the generic version of Action With A Type.
public void MakeCall(Action<TYPE_HERE> cmd)
{
cmd.Invoke(...);
}
The type gets inferred and intellisense should kick in.
So I got it. Iused an extension method. Thank you.
public static class MyStaticClass{
public static void MakeCall(Action<Cmds> paramater){
Helper(new Cmds(), parameter);
}
private static void Helper(this Cmds, Action<Cmds> invokeThis) {...}
public static void MakeCallTwo<???>( ??????)
}

Passing in <T> to a method where GetEnum<T> is called

I’m using an API that has an object that returns IEnumerable<T>, so something like Object.GetEnum<T>.
I have a method that within it will call GetEnum but I want to add to the method’s parameters the ability to pass the parameter type. So for example I want to do:
private void myMethod(apiClass??? apiclass)
{
IEnumerable< itemType > enumX = ObjectGetEnum< itemType >
}
private void Main()
{
myMethod(apiClass1);
myMethod(apiClass2);
}
So as above I don’t know what the parameter type should be in myMethod or how to write the code that gets the enumerator. I tried passing “apiClass”, the class which apiClass1 and apiClass2 inherit from. But then got stuck there on what to do…and I don’t think that really work anyways.
So I’m not sure if I just don’t know how in C# to do this, or if it is even possible, …. or perhaps I’m missing something in the API (or the API is missing something to facilitate this).
Thanks
FKC
Okay, I'm going to take a stab at this, although I'd like the question to be clarified. I suspect you just need to make the method generic:
private void MyMethod<TItem>() where TItem : ApiClass
{
IEnumerable<TItem> enumX = ObjectGetEnum<TItem>();
}
private static void Main()
{
MyMethod<ApiClass1>();
MyMethod<ApiClass2>();
}
Are you trying to access the type parameter of the closed constructed type inside a method? Maybe something like this will work:
using System;
class Foo<T> { }
class Program
{
static void Main()
{
myMethod(new Foo<String>());
}
private static void myMethod<T>(Foo<T> foo)
{
// use the T parameter in here
}
}
You need something like this:
private void myMethod<T>()
{
IEnumerable<T> enumX = ObjectGetEnum<T>();
}

Categories

Resources