Im having problems with dynamically calling a method - c#

I'm trying to dynamically call a method that accepts either a string or null. Im trying to build a command line program and I would like the commands to be able to accept no or some number of arguments. Here's the code to call the methods :
public class Command {
public static void Interpret(AST.Command Command) {
if (Command.command != null) {
typeof(Interpreter.Command).GetMethod(Command.command)?.Invoke(null, Command.args.ToArray());
}
}
public static void quit(string? args) {
System.Environment.Exit(1);
}
public static void info(string? args) {
Console.WriteLine("MathDoer Info :\n\tVersion : 0.0.1\n\tBy : Wiazarr");
}
}
It is my understanding that the question mark after the string in the method declaration allows the string to be null and thus making the variable null, and it works if I call the methods normally but not while calling it with the Invoke method. How can I fix this?

When calling by reflection, pass null or use Type.Missing to indicate a default argument. The argument count still has to match.
Here's some bare bones code I used to reproduce your issue. Does this help?
internal class Program
{
static void Main(string[] args)
{
Console.Title = "Invoke with Reflection";
var method = typeof(Command).GetMethod("info");
method?.Invoke(null, new object[] { "NOT NULL" });
method?.Invoke(null, new object[] { null });
Console.ReadKey();
}
}
Mock minimal
public class Command
{
public static void info(string? args)
{
if(string.IsNullOrWhiteSpace(args))
{
Console.WriteLine("Called null or empty");
}
else
{
Console.WriteLine($"Called with {(string)args}");
}
}
}
Default Value in C#
After reading your comment, I wanted to mention that ? the context of an argument means that a null value is allowed. This is different from having a default value.
This is easier to show with an int argument which ordinarily isn't nullable.
internal class Program
{
static void Main(string[] args)
{
var method = typeof(Command).GetMethod("methodWithInt");
// Without the '?' this will not compile
Command.methodWithInt(null);
method?.Invoke(null, new object[] { null });
method?.Invoke(null, new object[] { 1 });
// Without the '= 10' default value
// this throws a runtime exception
method?.Invoke(null, new object[] { Type.Missing });
}
}
public class Command
{
public static void methodWithInt(int? args = 10)
{
if(Equals(args, null))
{
Console.WriteLine("Called null.");
}
else
{
Console.WriteLine($"Called with {args}");
}
}
}

Related

How to use STATIC class value with LIST or LAMBDA EXPRESSION?

This is my sample code.
public class Sample
{
public void Main()
{
Execute01<DB_MS_A>();
Execute02<DB_MS_A>();
Execute01<DB_MS_B>();
Execute02<DB_MS_B>();
Execute01<DB_MS_C>();
Execute02<DB_MS_C>();
}
public void Execute01<DbModel>()
where DbModel : IDatabaseModel
{
// do something...
}
public void Execute02<DbModel>()
where DbModel : IDatabaseModel
{
// do something...
}
}
Not to waste code lines, I want to modify Main method code like below.
public void Main()
{
var dbList = new List<dynamic>() {
DB_MS_A,
DB_MS_B,
DB_MS_C
};
dbList.ForEach(db => {
Execute01<db>();
Execute02<db>();
});
}
But it seems impossible to add static value to List.
Also Delivering static value as lambda arguments is not possible.
Is there any way for method Refactoring?
I think you can simply use a list of type:
var listInputType = new []{
typeof(string),
typeof(int),
};
But I don't think you can pass run time type to generique as they need compile type.
But we can use reflexion like in this SO question: C# use System.Type as Generic parameter.
public class Program
{
public static void Main()
{
var listInputType = new []{
typeof(string),
typeof(int),
};
foreach(var myType in listInputType){
typeof(Program).GetMethod("M1").MakeGenericMethod(myType).Invoke(null, null);
typeof(Program).GetMethod("M2").MakeGenericMethod(myType).Invoke(null, null);
}
}
public static void M1<t>()
{
Console.WriteLine($"M1<{typeof(t).Name}>()");
}
public static void M2<t>()
{
Console.WriteLine($"M2<{typeof(t).Name}>()");
}
}
C# online demo

Call a method on a dynamic object by name

I'm trying to create a "wrapper" around a dynamic object so I can keep method names on dynamic object matching the names of the methods in the wrapping class.
What I need to do is provide the helper a dynamic object, and the name of the method i want to call on it (via [CallerMemberName]), and the args for the call. I can't figure out how to invoke the call on the dynamic object. How can I do this?
class Program
{
static void Main(string[] args)
{
var dyn = new ClassWithDynamicProperty();
dyn.SendMessage("test");
Console.ReadKey();
}
}
public class ExampleDynamicClass
{
public void SendMessage(string msg)
{
Console.WriteLine(msg);
}
}
public class ClassWithDynamicProperty
{
public ClassWithDynamicProperty()
{
MyDynObject = new ExampleDynamicClass();
}
public dynamic MyDynObject { get; set; }
public void SendMessage(string theMessage)
{
//i want to replace this:
MyDynObject.SendMessage(theMessage);
//with this:
DynamicHelper.CallDynamic(MyDynObject, new object[] { theMessage });
}
}
public static class DynamicHelper
{
public static void CallDynamic(dynamic source, object[] args, [CallerMemberName]string methodName = null)
{
//source.methodName(args); How can i invoke this?
}
}
Turns out it's not that hard after all. I didn't know if normal reflection would work with dynamic types. All resources I found for dynamic objects involved overriding TryInvokeMember, which wasn't an option. Here's missing code:
var method = ((object)dynamicObject).GetType().GetMethod(methodName);
method.Invoke(dynamicObject, args);

C#: Generics, Polymorphism And Specialization

I am trying to use generics with specialization. See the code below. What I want to do is make runtime engine understand that specialization of the function is available based on type and it should use that instead of generic method. Is it possible without using keyword dynamic?
public interface IUnknown
{
void PrintName<T>(T someT);
}
public interface IUnknown<DerivedT> : IUnknown
{
//***** I am trying to make runtime engine understand that method below is
//***** specialization of void PrintName<T>(T someT);
void PrintName(DerivedT derivedT);
}
public class SoAndSo<DerivedT> : IUnknown<DerivedT>
{
public void PrintName<T>(T someT) { Console.WriteLine("PrintName<T>(T someT)"); }
public void PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
}
public class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<string>());
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[0].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName("abc");
//********** code snippet below works exactly as expected ************
dynamic d;
d = unknowns[0];
d.PrintName(10); // <=== prints "PrintName(DerivedT derivedT)"
d.PrintName("abc"); // <=== prints "PrintName<T>(T someT)"
}
}
EDIT
If there isn't any way to achieve what I want without use of keyword dynamic, could there be any elegant way to achieve casting to concrete type without huge enum\flag\switch-case?
EDIT - POSSIBLY ONE WAY OF ACHIEVING THIS
I wanted to post this as an answer but this is not really based on polymorphism or overloading so decided to put as an edit instead. Let me know if this makes sense.
public abstract class IUnknown
{
public abstract void PrintName<T>(T someT);
}
public abstract class IUnknown<DerivedT /*, DerivedType*/> : IUnknown //where DerivedType : IUnknown<DerivedT, DerivedType>
{
MethodInfo _method = null;
//***** I am trying to make runtime engine understand that method below is
//***** specialization of void PrintName<T>(T someT);
public override sealed void PrintName<T>(T derivedT)
{
bool isSameType = typeof(T) == typeof(DerivedT);
if (isSameType && null == _method)
{
//str = typeof(DerivedT).FullName;
Type t = GetType();
_method = t.GetMethod("PrintName", BindingFlags.Public |
BindingFlags.Instance,
null,
CallingConventions.Any,
new Type[] { typeof(T) },
null);
}
if (isSameType && null != _method)
{
_method.Invoke(this, new object[] { derivedT });
}
else
{
PrintNameT(derivedT);
}
}
public virtual void PrintNameT<T>(T derivedT)
{
}
public virtual void PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
//public static DerivedType _unknownDerivedInstance = default(DerivedType);
}
public class SoAndSo<DerivedT> : IUnknown<DerivedT> //, SoAndSo<DerivedT>>
{
//static SoAndSo() { _unknownDerivedInstance = new SoAndSo<DerivedT>(); }
public override void PrintNameT<T>(T someT) { /*Console.WriteLine("PrintNameT<T>(T someT)");*/ }
public override void PrintName(DerivedT derivedT) { /*Console.WriteLine("PrintName(DerivedT derivedT)");*/ }
}
public static class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<float>());
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[0].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName(10.3);
//*** statement below should print "PrintName(DerivedT derivedT)"
unknowns[1].PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[1].PrintName(10.3f);
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
for (int i = 0; i < 1000000; ++i)
{
unknowns[0].PrintName(10.3);
}
stopWatch.Stop();
System.Diagnostics.Trace.TraceInformation("Milliseconds: {0}", stopWatch.ElapsedMilliseconds);
//********** code snippet below works exactly as expected ************
dynamic d;
d = unknowns[0];
d.PrintName(10); // <=== prints "PrintName(DerivedT derivedT)"
d.PrintName("abc"); // <=== prints "PrintName<T>(T someT)"
}
Thanks in advance,
-Neel.
I don't believe there's any way of doing this. It's simply not part of the execution-time dispatch mechanism which the CLR supports. You could write this, of course:
public void PrintName<T>(T someT)
{
// This is assuming you want it based on the type of T,
// not the type of the value of someT
if (typeof(DerivedT).IsAssignableFrom(typeof(T))
{
PrintName((DerivedT)(object) someT);
return;
}
Console.WriteLine("PrintName<T>(T someT)");
}
... but that's not terribly pleasant.
You could achieve this with an explicit implementation of IUnknown<DerivedT>. However, I'm not sure this is what you are looking for.
public class SoAndSo<DerivedT> : IUnknown<DerivedT>
{
public void PrintName<T>(T someT) { Console.WriteLine("PrintName<T>(T someT)"); }
void IUnknown<DerivedT>.PrintName(DerivedT derivedT) { Console.WriteLine("PrintName(DerivedT derivedT)"); }
}
public class Test
{
public static void TestIt()
{
List<IUnknown> unknowns = new List<IUnknown>();
unknowns.Add(new SoAndSo<int>());
unknowns.Add(new SoAndSo<string>());
//*** statement below should print "PrintName(DerivedT derivedT)"
(unknowns[0] as IUnknown<int>).PrintName(10);
//*** statement below should print "PrintName<T>(T someT)"
unknowns[0].PrintName("abc");
}
}
I would suggest defining a generic static class NamePrinter<T>, with an Action<T> called PrintName, which initially points to a private method that checks whether T is a special type and either sets PrintName to either a specialized version or the non-specialized version (the non-specialized version could throw an exception if desired), and then invokes the PrintName delegate. If one does that, the first time one calls NamePrinter<T>.PrintName(T param) for any particular T, code will have to inspect type T to determine which "real" method to use, but future calls will be dispatched directly to the proper routine.

Getting target of Action

I have created the fallowing Sample-Code:
class Program {
static void Main(string[] args) {
var x = new ActionTestClass();
x.ActionTest();
var y = x.Act.Target;
}
}
public class ActionTestClass {
public Action Act;
public void ActionTest() {
this.Act = new Action(this.ActionMethod);
}
private void ActionMethod() {
MessageBox.Show("This is a test.");
}
}
When I do this on this way, y will an object of type ActionTestClass (which is created for x). Now, when I change the line
this.Act = new Action(this.ActionMethod);
to
this.Act = new Action(() => MessageBox.Show("This is a test."));
y (the Target of the Action) will be null. Is there a way, that I can get the Target (in the sample the ActionTestClass-object) also on the way I use an Anonymous Action?
The lack of Target (iow == null) implies the delegate is either calling a static method or no environment has been captured (iow not a closure, just a 'function pointer').
the reason why you see the target as empty is because the anonymous method is not part of any class. If you open your program in reflector, it will show you the code that is generated by the compiler, here you will see the following
public void ActionTest()
{
this.Act = delegate {
Console.WriteLine("This is a test.");
};
}
You can use the following:
Act.Method.DeclaringType

Using delegates with arguments

I have a class 'KeyEvent'; one of which's members is:
public delegate void eventmethod(object[] args);
And the method passed to the object in the constructor is stored in this member:
private eventmethod em;
Constructor:
public KeyEvent(eventmethod D) {
em = D;
}
public KeyEvent(eventmethod D, object[] args) : this(D) {
this.args = args;
}
public KeyEvent(Keys[] keys, eventmethod D, object[] args) : this(keys, D) {
this.args = args;
}
The 'eventmethod' method is then called by using the public method "ThrowEvent":
public void ThrowEvent() {
if (!repeat && thrown) return;
em.DynamicInvoke(args);
this.thrown = true;
}
As far as I can see, this compiles fine. But when trying to create an instance of this class (KeyEvent), I'm doing something wrong. This is what I have so far:
object[] args = {new Vector2(0.0f, -200.0f)};
Keys[] keys = { Keys.W };
KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);
GameBase.ChangeSquareSpeed doesn't do anything at the moment, but looks like this:
static public void ChangeSquareSpeed(Vector2 squarespeed) {
}
Anyway, the erroneous line is this one:
KeyEvent KeyEvent_W = new KeyEvent(keys, new KeyEvent.eventmethod(GameBase.ChangeSquareSpeed), args);
The error that the compiler gives me is:
error CS0123: No overload for 'ChangeSquareSpeed' matches delegate 'BLBGameBase.KeyEvent.eventmethod'
My question is: Does this mean I have to change ChangeSquareSpeed to take no parameters (in which case, what is a better way of doing this?), or am I doing something syntactically wrong?
Thank you in advance.
I think the error is very explicit. Your ChangeSquareSpeed method doesn't match the delegate . The delegate expects a method with one object[] as parameter but your passing a method with a Vector2 as a parameter, hence the error.
Try this method:
static public void ChangeSquareSpeed(object[] squarespeed)
{}
(update)
I see some confusion in your code, specially in the line:
object[] args = {new Vector2(0.0f, -200.0f)};
I can't really understand if you want an array of Vector2's or just a Vector2's object.
If you pretend to have an array of Vector2's I think this might seem reasonable:
Change the delegate to:
public delegate void eventmethod(Vector2 args);
and then
public void ThrowEvent() {
if (!repeat && thrown) return;
foreach(object obj : args)
{
em.DynamicInvoke((Vector2)obj);
}
this.thrown = true;
}
(update 2)
In that case, I think you should create a generic version of KeyEvent. See this example and go from there:
class KeyEvent<T>
{
public T Args { get; set; }
public Action<T> A { get; set; }
public KeyEvent() { }
public void ThrowEvent()
{
A.DynamicInvoke(Args);
}
}
// ...
static void M1(object[] o)
{
Console.WriteLine("M1 {0}", o);
}
static void M2(Vector2 v)
{
Console.WriteLine("M2 {0}", v);
}
static void Main(string[] args)
{
KeyEvent<object[]> e1 = new KeyEvent<object[]>
{
A = new Action<object[]>(M1),
Args = new object[] {};
};
KeyEvent<Vector2> e2 = new KeyEvent<Vector2>
{
A = new Action<Vector2>(M2),
Args = new Vector2();
};
}
The delegate eventmethod states that all events using it should take object[] (args) as their only in parameter. Depending on what you're using this code for, you want to either:
Change the signature of ChangeSquareSpeed to ChangeSquareSpeed(object[] squarespeed)
Create a new delegate, with the signature void neweventmethod(Vector2 args); and use that
Change the signature of eventmethod to the above
If you are on C# 3, change the delegate to an Action<object[]>. That will make your life much simpler, as it will be type-safe to invoke it.
That would allow you to simply invoke it like this:
this.em(args);
and you would have compile-time checking instead.

Categories

Resources