I have recently begun working with C# and there is something I used to do easily in Python that I would like to achieve in C#.
For example, I have a function like:
def my_func():
return "Do some awesome stuff"
And a dictionary like:
my_dic = {"do": my_func}
I have made a script in which when the user would input "do", the program would call my_func according to the dictionary.
I'd like to know how I can assign functions to strings in a C# dictionary.
Basically in the same way:
static void Main() {
var dict = new Dictionary<string, Action>();
// map "do" to MyFunc
dict.Add("do", MyFunc);
// run "do"
dict["do"]();
}
static void MyFunc() {
Console.WriteLine("Some stuff");
}
You can take advantage of the collection initializer syntax here.
var my_dic = new Dictionary<string, Action>
{
{ "do", my_func }
};
For more sophisticated functions, you'd replace Action in the declaration with the appropriate Function type.
The C# code fragments that would be most directly analogous to your examples are:
string my_func() {
return "Do some awesome stuff";
}
And:
var my_dic = new Dictionary<string, Func<string>> {
{ "do", my_func },
};
The trick, as the other posters have pointed out, is to create a string whose generic value type is of either an Action (which is a method that returns void) or a Func<T> (which is a method that returns an object of type T).
In either case, you could then execute the method with:
var result = my_dic["do"]();
If you truly want the dynamic behavior of Python (i.e. being able to seamlessly assign and call methods that have different signatures to a "dictionary"), I'd go with the ExpandoObject which was specifically meant to be able to have the CLR support dynamic languages such as Python (see IronPython, et al).
static void Main()
{
dynamic expando = new ExpandoObject();
expando.Do = new Func<string>(MyFunc);
expando.Do2 = new Func<string, string>(MyFunc2);
Console.WriteLine(expando.Do());
Console.WriteLine(expando.Do2("args"));
}
static string MyFunc()
{
return "Do some awesome stuff";
}
static string MyFunc2(string arg)
{
return "Do some awesome stuff with " + arg;
}
If you prefer, you can even treat an ExpandoObject as a dictionary:
static void Main(string[] args)
{
dynamic expando = new ExpandoObject();
var dict = (IDictionary<string, object>) expando;
dict["Do"] = new Func<string>(MyFunc);
dict["Do2"] = new Func<string, string>(MyFunc2);
Console.WriteLine(expando.Do());
Console.WriteLine(expando.Do2("args"));
}
static string MyFunc()
{
return "Do some awesome stuff";
}
static string MyFunc2(string arg)
{
return "Do some awesome stuff with " + arg;
}
** Edit **
Full disclosure: This question seems very similar (if not a dupe) of String- Function dictionary c# where functions have different arguments, which I just answered the same way.
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 looking for a way to get hold of the name of a variable that was passed into an extensionmethod. I want to have the name of the parameter in the calling variable. Sounds strange, let me explain.
assume this piece of testing code
private static void TestingMethod(string firstParam, int secondParam, bool thirdParam)
{
try
{
throw new InvalidOperationException("This named optional params stuff, it's just not working boss");
}
catch (Exception ex)
{
GenericLog_Exception(ex, "it's on fire, please help");
}
}
On the last line you can see the exception being logged. I want to be able to provide optional parameter support. So the developers can add parameter information when needed.
I've seen many posts about this on stackoverflow, lot's of different approaches. Main thing is; it can't be done fully generically.
Some code for explanation:
static string GetCallingMethodSignature()
{
StackTrace stackTrace = new StackTrace();
// Get calling method name
var callingMethod = stackTrace.GetFrame(1).GetMethod();
var callingMethod_Name = callingMethod.Name;
// get calling method params
string retVal = string.Empty;
var callingMethod_Parameters = callingMethod.GetParameters();
retVal = callingMethod_Name + "(";
foreach (var param in callingMethod_Parameters)
{
retVal += param.Name + ": " + param.ToString() + ",";
}
retVal.Remove(retVal.Length - 1, 1);
retVal += ")";
return retVal;
}
Now, this testing code is getting the calling method name and it's parameters. That is, the names of the parameters. But not their values. The param.tostring() part only returns the type name. Not the value. I've been reading on this and it seems this can't be done via reflection.
So then I went for another approach, why not provide the parameters the developer finds suitable for logging. You don't need all of them most of the time anyway.
private static string GenericLog_Exception(Exception exceptionData, string extraInformation, params KeyValuePair<string, object>[] parameters)
So, this being a new testmethod, i'm providing the parameters of choice into the exception logging method. But if you want to make this work, it's one hell of a job everytime to make this call.
private static void TestingMethod(string firstParam, int secondParam, bool thirdParam)
{
try
{
throw new InvalidOperationException("This named optional params stuff, it's just not working boss");
}
catch (Exception ex)
{
GenericLog_Exception(ex, "it's on fire, please help", new KeyValuePair<string, object>[]{
new KeyValuePair<string, object>("firstParam", firstParam),
new KeyValuePair<string, object>("secondParam", secondParam),
new KeyValuePair<string, object>("thirdParam", thirdParam)
});
}
}
Now this is working. But as said, i find the bottom part to cumbersome. I was thinking along the lines of an extensionmethod, so I can shorten the creation of each kvp.
internal static class ExtensionMethodsForTesting
{
internal static KeyValuePair<string, object> AsKeyValuePair(this string parameter)
{
var name = nameof(parameter);
return new KeyValuePair<string, object>(name, parameter);
}
}
And this would then be used as
GenericLog_Exception(ex, "it's on fire, please help", new KeyValuePair<string, object>[] { firstParam.AsKeyValuePair() });
This confronts me with the same issue I had before; the nameof(parameter), ofcourse, returns "parameter". I would also have to make a couple of extension methods for each type. Or check for the type in the extension method to make sure i get the correct value.
So, in short: how can i get the name of this variable that invokes the extension method?
You could do the following "hack". Change the signature of your method to the following:
private static string GenericLog_Exception(
Exception exceptionData,
string extraInformation,
params Expression<Func<object>>[] parameters)
And now your call site would look a little bit cleaner:
GenericLog_Exception(ex,
"it's on fire, please help",
() => firstParam,
() => secondParam,
() => thirdParam);
And you can extract parameter info from the expressions the following way (using C# tuple support for convenience):
private static (object Value, string ParamName) GetParameterInfo
(Expression<Func<object>> expr)
{
//First try to get a member expression directly.
//If it fails we know there is a type conversion: parameter is not an object
//(or we have an invalid lambda that will make us crash)
//Get the "to object" conversion unary expression operand and then
//get the member expression of that and we're set.
var m = (expr.Body as MemberExpression) ??
(expr.Body as UnaryExpression).Operand as MemberExpression;
return (expr.Compile().Invoke(), m.Member.Name);
}
To help me learn c#, I am converting a script I made in lua to C#
I want to know if it is possible to add a function to a list (table in lua) and call it
Here's what I have in Lua
functions{ function() print("Hello World!") end }
functions[1]()
Output: Hello World!
In C# I am using Lists
Example
var functions = new List</* What do I put here */>();
functions.Add(/* Somehow define a public static void here */);
Thank you.
Use Action or Func<TResult> depending whether you need result or not, use lambda expression to define function in style you are looking for:
var functions = new List<Action>();
functions.Add(() => { Console.WriteLine("Here!"); }
functions[0]();
Awesome! Well, I can't say with certainty that this is the best answer, but it's my take on the this situation.
class Program
{
static void Main(string[] args)
{
var functions = new List<Action>();
functions.Add(new Action(delegate
{
// Do stuff
Console.WriteLine("Successfully did stuff.");
}));
functions[0].DynamicInvoke();
Console.ReadKey();
}
}
Actions in .NET are used a lot with the Task Parallel Library.
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;
}
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;
}
}