How do I call the correct overloaded function given a reference to an object based on the actual type of the object. For example...
class Test
{
object o1 = new object();
object o2 = new string("ABCD");
MyToString(o1);
MyToString(o2);//I want this to call the second overloaded function
void MyToString(object o)
{
Console.WriteLine("MyToString(object) called.");
}
void MyToString(string str)
{
Console.WriteLine("MyToString(string) called.");
}
}
what I mean is there a better option than the following?
if(typeof(o) == typeof(string))
{
MyToString((string)o);
}
else
{
MyToString(o);
}
May be this can be done using reflection?
Ok as soon as I hit post I remembered this can indeed be done using reflection...
var methInfo = typeof(Test).GetMethod("MyToString", new Type[] {o.GetType()});
methInfo.Invoke(this, new object[] {o});
You could just use ternary operators to code this using a single clean line of code:
MyToString(o is string ? (string)o : o);
Why not have a toString() function in the actual object itself? That way you can call myObj.toString() and the relative output is given. Then you don't have to do any comparisons.
Related
I'm generating a random number from 1-1000. I have 200 functions named function1, function4, function 10, function 11, etc. What I would like to do is execute a specific function depending on if the number generated requires a function, and ignore it if not.
My first thought was to create an int[] containing all of the values that would trigger a function, and if the int[] contains the random number to use if statements to figure out what the number is. I'm concerned that it must be a really crude solution to an easy problem though.
I know the "best way" to do something is subjective, but is there a better way to accomplish this?
UPDATE: As per comments, I should probably have started out by pointing out that doing this for 200 functions is probably a good sign that there is some serious issue in your design. This is probably an XY question where you are trying to solve a problem in some crazy way and asking about your intended solution instead of asking about the problem itself.
That said I'll leave the original answer because it's still good advice when mapping a reasonable amount of function calls that can/will change during the life cylce of your app or dynamically as the code runs.
I won't get into why you are doing this, but I'll try to at least point you in the right direction so this doesn't become a complete nightmare when you need to modify/expand behavior:
You can map numbers to function calls using delegates and a dictionary. Assuming your functions take no arguments and return void you'd do:
var functionsMap = new Dictionary<int, Action>();
//map functions
var r = getSomeRandomNumber();
if (functions.TryGetValue(r), out var a)
a(); //invoke function
Mapping functions is simply adding keys and values:
functionsMap.Add(1, () => function1());
functionsMap.Add(3, () => function3());
//etc.
If your functions take arguments or return values, you'd use the adequate delegate: Action<T>, Func<T1, T2> etc.
You can use reflection to invoke appropriate method:
Type exampleType = exampleObject.GetType();
MethodInfo exampleMethod = exampleType.GetMethod(methodName);
exampleMethod.Invoke(this, null);
Where methodName can be created using your random number.
Without commenting on the wisdom of having 200 functions named the way yours are, you can use reflection to determine whether a given functionX() exists, like so:
public void ExecuteDynamicMethod(int number)
{
// Modify these two lines with your app's dll/exe and class type:
Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
Type type = assembly.GetType("YourClassType");
if (type != null)
{
MethodInfo methodInfo = type.GetMethod("function" + number);
if (methodInfo != null)
{
object classInstance = Activator.CreateInstance(type, null);
methodInfo.Invoke(classInstance, null); // null = "no function arguments"
}
}
}
This can then be called for a given value like
ExecuteDynamicMethod(14);
See this SO answer for the inspiration behind this.
Reflection can be used for this purpose. I want to give and keep below example for not only the objective of the question but also for future reference. Also, of course that many function is not good but below code shows the approach that can work with many functions if they have similar name (like starting with "function" keyword).
Assume below is Methods.cs
using System;
using System.Reflection;
namespace YourMethodNamespace
{
public class YourMethodClass
{
public void function1()
{
Console.WriteLine("Function-1");
}
public void function2()
{
Console.WriteLine("Function-2");
}
...
public void function200()
{
Console.WriteLine("Function-200");
}
public static void invokeMethodsDynamically(int randomNumber){
Type yourClassType = typeof(YourMethodClass);
ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(Type.EmptyTypes);
object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{});
//If the constructor has parameters, then we can pass them by this way. Like below;
/*ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(new[]{typeof(int)});
object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{3});
*/
MethodInfo[] methodInfoArr = yourClassType.GetMethods();
foreach(MethodInfo methodInfo in methodInfoArr){
if(methodInfo.Name == "function" + randomNumber){
methodInfo.Invoke(yourClassObject, null);
}
}
}
}
}
Let's say below is Program.cs
using System;
using YourMethodNamespace;
namespace YourProgramNamespace
{
public class YourProgramClass
{
public static void Main()
{
Random random = new Random();
int randomNumber = random.Next(1, 201);
//If Methods.cs is in another Assembly
/*string pathToDllAssembly = #"Domain.dll";
Assembly dllAssembly = Assembly.LoadFrom(pathToDllAssembly);
Type methodsClassType = dllAssembly.GetType("YourMethodNamespace.YourMethodClass");
ConstructorInfo methodClassConstructorInfo = methodsClassType.GetConstructor(Type.EmptyTypes);
object methodsClassObject = methodClassConstructorInfo.Invoke(new object[]{});
MethodInfo methodInfo = methodsClassType.GetMethod("invokeMethodsDynamically");
methodInfo.Invoke(methodsClassObject, new object[]{randomNumber});
*/
YourMethodClass.invokeMethodsDynamically(randomNumber, null);
}
}
}
Also for testing and observing, below link can be used.
https://repl.it/#erdsavasci/ReflectionTest
I'm using repository structure in my application.
I have a interface class IDemoService
public interface IDemoService
{
bool CreateDemo(Demo demo);
bool UpdateDemo(Demo demo);
bool DeleteDemo(int id);
Demo GetDemo(int id);
Demo GetDemoServiceByName(string name);
IEnumerable<Demo> GetAllDemo();
void SaveRecord();
}
with using System.Reflection; I need to create reference like
IDemoService iDemoService;
I've tried this way so far:
var iDemoServiceClass = asm.GetTypes().Where(p =>
p.Namespace == nameSpace &&
p.Name == "IDemoService"
).ToList();
Type iDemoServiceClassType = iDemoServiceClass.FirstOrDefault();
var className = iDemoServiceClassType.Name;
var functionName = "Get" + iDemoServiceClassType + "ByName";
MethodInfo getMethod = demoServiceClassType.GetMethod(functionName);
var instanceCreate = Activator.CreateInstance(iDemoServiceClassType);//, null); //here I want to create reference instead instance
ParameterInfo[] parameters = getMethod.GetParameters();
if (parameters.Length > 0)
{
object[] parametersArray = new object[] { "RequiredDemo" };
var demoObj = getMethod.Invoke(instanceCreate, parametersArray);
}
Since it is interface so can't create instance but reference is possible. So, is it possible anyway to create reference using Reflection or any other way?
Please help me right way. Thanks advance :D
You can't instantiate an interface, and so you can't create a reference to it. You need a concrete type implementing that interface, than you can use Activator.CreateInstance.
The point is that an interface is just a contract, not a real implementation; so for example you have no method bodies. Imagine the compiler letting you activate the interface, what is supposed to happen when you call a method without a body?
At least you need an empty class in the form DemoService:IDemoService, than you get a reference to it.
Hope it helps.
ok, so in javascript, we can declare an object like this,
var obj={name:"Irshu",age:22};
console.log(obj);
How do we do the same in c#? the reason i ask because my function need to return a string and a bool together. I dont want to create a class for it, and i dont want to use the dictionary. Are there any alternatives?
public void Message(){
var obj=GetObject(val);
Messagebox.Show(Convert.ToString(obj.ind));
}
public object GetObject(string val){
return new {ind=val,flag=true};
}
This is not valid, is it?
.Net supports ExpandoObject since .NET 4.
http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.110%29.aspx
It lets you declare the object and add properties as your would in javascript.
Traditionally it is for JS interop and I can't recommend it for production work. Tuple<T> is more appropriate as you get strong typing for free. Ultimately you will write less code and see less runtime errors.
What you have in your code is an anonymous type. Anonymous types cannot exist outside the scope in which they are declared. Generally, we use these for transforming LINQ results to temporary objects.
You can't return anonymous types from a method. You can do however something like this:
public void Message(){
var obj = new { ind = "oaiwejf", flag = true };
Messagebox.Show(obj.ind);
}
EDIT
Check this MSDN article
turns out, its posible, one genius on the internet posted this:
public void Message()
{
var obj=GetObject("Irshu");
var y= Cast(obj, new { ind= "", flag= true });
Messagebox.Show(y.ind); //alerts Irshu
}
public object GetObject(string val){
return new {ind=val,flag=true};
}
T Cast<T>(object obj, T type)
{
return (T)obj;
}
i'm trying to hand over a Dynamic object to Ironpython, but it seems Ironpython is not calling TryInvokeMember. Instead it calls TryGetMember and gives an Error that it cant call the result.
I have tried it with IronPython 2.7 and 2.6.10920
ExampleCode:
DynamicObject:
class ExampleDynamicObject: DynamicObject {
public override bool TryGetMember(GetMemberBinder binder,
out object result) {
result = "TryGetMember";
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args,
out object result) {
result = "TryInvokeMember";
return true;
}
}
calling Mathode
static void Main(string[] args) {
dynamic example = new ExampleDynamicObject();
var program = #"test = example.Call2(2)";
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
scope.SetVariable("example", example);
var source = engine.CreateScriptSourceFromString(program,
SourceCodeKind.Statements);
source.Execute(scope);
Console.ReadKey();
}
This calls the TryGetMember method and then throws a Microsoft.Scripting.ArgumentTypeException "str is not callable"
This is thrown when u code something like 'test'(1)
So it seems that Python doesn't get that this is a Function call and instead just calls a Property.
But when i try to call it from C#
Console.WriteLine(example.Call);
Console.WriteLine("----------------------------");
Console.WriteLine(example.Call(1));
This will work:
TryGetMember
-------------------
TryInvokeMember
Has anyone a suggestion how to fix this?
Solution: (edit: calledMethodeName has to be a List, otherwise nested methods wouldn't work)
So thanks to Jeff.
When i design the Dynamic like that:
List<string> calledMethodeNames = new List<string>();
public override bool TryGetMember(GetMemberBinder binder,
out object result)
{
calledMethodeNames.Add(binder.Name);
result = this;
return true;
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
//calledMethodeNames last Element has stored the Name of the called methode (remeber to remove it)
result = "TryInvoke";
return true;
}
everything is working fine.
The clue is to return the Object itself as Member, than the object is callable and python calls the TryInvoke (not TryInvokeMember)
But TryInvoke ist called because after returning the object, the object itself is called. So InvokeBinder dont knows the Name of the called methode. So i store it into a variable.
That's the expected behaviour. IronPython uses TryGetMember followed by TryInvoke since the Python language has no concept of invoking a member: Python method calls are always an attribute lookup followed by a call.
The error you're getting is because you're setting result to a string (type str) and strings are not callable. You'll have to set result to either another dynamic object that implements TryInvoke or a delegate.
Based on the Python exception (str is not callable) it looks like IronPython first calls TryGetMember and since that function returns true it will use that object.
The TryGetMember/TryInvokeMember should only return true if they succeeded. For example that means TryGetMember should return true if and only if there actually is a member that matches the binder parameter.
Update: in C# Call(2) is always a method call (I can't think of anything else it could be, please let me know if I'm wrong), so the C# compiler will use TryInvokeMethod. In Python however any object is callable if it has a __call__ method, so Call(2) could either mean execute the method Call or get the member Call and execute __call__ on it.
First of all, sorry if this has been asked before. I've done a pretty comprehensive search and found nothing quite like it, but I may have missed something.
And now to the question: I'm trying to invoke a constructor through reflection, with no luck. Basically, I have an object that I want to clone, so I look up the copy constructor for its type and then want to invoke it. Here's what I have:
public Object clone(Object toClone) {
MethodBase copyConstructor = type.GetConstructor(
new Type[] { toClone.GetType() });
return method.Invoke(toClone, new object[] { toClone }); //<-- doesn't work
}
I call the above method like so:
List<int> list = new List<int>(new int[] { 0, 1, 2 });
List<int> clone = (List<int>) clone(list);
Now, notice the invoke method I'm using is MethodBase's invoke. ConstructorInfo provides an invoke method that does work if invoked like this:
return ((ConstructorInfo) method).Invoke(new object[] { toClone });
However, I want to use MethodBase's method, because in reality instead of looking up the copy constructor every time I will store it in a dictionary, and the dictionary contains both methods and constructors, so it's a Dictionary<MethodBase>, not Dictionary<ConstructorInfo>.
I could of course cast to ConstructorInfo as I do above, but I'd rather avoid the casting and use the MethodBase method directly. I just can't figure out the right parameters.
Any help? Thanks so much.
EDIT
Benjamin,
Thanks so much for your suggestions. I was actually doing exactly what you suggest in your second edit, except (and that's a big "except") my dictionary was where
class ClonerMethod {
public MethodBase method;
public bool isConstructor;
...
public Object invoke(Object toClone) {
return isConstructor ?
((ConstructorInfo) method).Invoke(new object[] { toClone }) : //<-- I wanted to avoid this cast
method.Invoke(toClone, null);
}
}
And then I called ClonerMethod's invoke on what I found in the dictionary. I didn't add the code the deals with all that because the answer I was looking for was just how to call Invoke on a ConstructorInfo using MethodBase's Invoke method, so I didn't want to add unnecessary info and too much code for you guys to read through. However, I like your use of Func<,> much MUCH better, so I'm switching to that. Also making the Clone method generic is a nice addition, but in my case the caller doesn't know the type of the object, so I'll keep it non-generic instead.
I didn't know about Func<,>, and if I knew about the lambda operator I had forgotten (I hadn't really needed something like this before), so I've actually learnt a lot from your answer. I always love to learn new things, and this will come in very handy in the future, so thanks a lot! :)
If you know that the object is having a constructor like that, did you think about using this overload of Activator.CreateInstance instead?
Update: So you have a cascading search for MethodInfo/MethodBase already and store them -> You don't want/cannot use Activator.
In that case I don't see a way to do what you want without a cast. But - maybe you could change the architecture to store a Dictionary<Type, Func<object, object>> and add those Func<> instances instead. Makes the calling code nicer (I assume) and would allow you to do this cast once:
// Constructor
dictionary.Add(type,
source => ((ConstructorInfo) method).Invoke(new object[] {source})
);
// Clone
dictionary.Add(type,
source => method.Invoke(source, new object[]{})
);
In fact, since you only care about the difference between constructor and normal method at the very site where you grab them, you wouldn't need a cast at all, would you?
// Constructor 2
dictionary.Add(type,
source => yourConstructorInfo.Invoke(new object[] {source})
);
Unless I'm missing something (quite possible, of course) this could resolve the problem by doing this once on the defining side of the fence and the caller wouldn't need to mind if this is constructor or not?
One last time, then I'm going to stop the edit spam. I was bored and came up with the following code. Is that what you are trying to accomplish?
public class Cloner {
private readonly IDictionary<Type, Func<object, object>> _cloneMap =
new Dictionary<Type, Func<object, object>>();
public T Clone<T>(T source) {
Type sourceType = source.GetType();
Func<object, object> cloneFunc;
if (_cloneMap.TryGetValue(sourceType, out cloneFunc)) {
return (T)cloneFunc(source);
}
if (TryGetCopyConstructorCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
if (TryGetICloneableCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
return default(T);
}
private bool TryGetCopyConstructorCloneFunc(Type type,
out Func<object, object> cloneFunc) {
var constructor = type.GetConstructor(new[] { type });
if (constructor == null) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => constructor.Invoke(new[] { source });
return true;
}
private bool TryGetICloneableCloneFunc(Type type,
out Func<object, object> cloneFunc) {
bool isICloneable = typeof(ICloneable).IsAssignableFrom(type);
var cloneMethod = type.GetMethod("Clone", new Type[] { });
if (!isICloneable || (cloneMethod == null)) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => cloneMethod.Invoke(source, new object[] {});
return true;
}
}