I have a message coming into my C# app which is an object serialized as JSON, when i de-serialize it I have a "Name" string and a "Payload" string[], I want to be able to take the "Name" and look it up in a function dictionary, using the "Payload" array as its parameters and then take the output to return to the client sending the message, is this possible in C#?
I've found a stack overflow answer here where the second part seems plausible but i don't know what I'm referencing with State
It sounds like you probably want something like:
Dictionary<string, Func<string[], int>> functions = ...;
This is assuming the function returns an int (you haven't specified). So you'd call it like this:
int result = functions[name](parameters);
Or to validate the name:
Func<string[], int> function;
if (functions.TryGetValue(name, out function))
{
int result = function(parameters);
...
}
else
{
// No function with that name
}
It's not clear where you're trying to populate functions from, but if it's methods in the same class, you could have something like:
Dictionary<string, Func<string[], int>> functions =
new Dictionary<string, Func<string[], int>>
{
{ "Foo", CountParameters },
{ "Bar", SomeOtherMethodName }
};
...
private static int CountParameters(string[] parameters)
{
return parameters.Length;
}
// etc
You can create a dictionary of string as a key and a Action<string[]> as a value and use it, for sample:
var functions = new Dictionary<string, Action<string[]>>();
functions.Add("compute", (p) => { /* use p to compute something*/ });
functions.Add("load", (p) => { /* use p to compute something*/ });
functions.Add("process", (p) => { /* use p to process something*/ });
You could use it after you deserialize your message parameter, you could use the functions dictionary:
public void ProcessObject(MessageDTO message)
{
if (functions.ContainsKey(message.Name))
{
functions[name](message.Parameters);
}
}
Yes.
var functions = new Dictionary<string, Func<string[], string[]>>();
functions.Add("head", x => x.Take(1).ToArray());
functions.Add("tail", x => x.Skip(1).ToArray());
var result = functions["tail"](new [] {"a", "b", "c"});
Something similar to this:
public class Methods
{
public readonly Dictionary<string, Func<string[], object>> MethodsDict = new Dictionary<string, Func<string[], object>>();
public Methods()
{
MethodsDict.Add("Method1", Method1);
MethodsDict.Add("Method2", Method2);
}
public string Execute(string methodName, string[] strs)
{
Func<string[], object> method;
if (!MethodsDict.TryGetValue(methodName, out method))
{
// Not found;
throw new Exception();
}
object result = method(strs);
// Here you should serialize result with your JSON serializer
string json = result.ToString();
return json;
}
public object Method1(string[] strs)
{
return strs.Length;
}
public object Method2(string[] strs)
{
return string.Concat(strs);
}
}
Note that you could make it all static, if the methods don't need to access data from somewhere else.
The return type I chose for the delegates is object. In this way the Execute method can serialize it to Json freely.
My solution with input parameters, and a int as Key of Invoke:
private static Dictionary<int, Action> MethodDictionary(string param1, string param2, int param3) => new Dictionary<int, Action>
{
{1 , () => Method1(param1, param2, param3) },
{2 , () => Method2(param1, param2, param3) },
{3 , () => Method3(param1, param2, param3) },
{4 , () => Method4(param1, param2, param3) },
{5 , () => Method5(param1, param2, param3) }
};
And to invoke a method:
var methodDictionary = MethodDictionary("param1", "param2", 1);
methodDictionary[2].Invoke();
This will execute Method2.
Hope it helps!
Related
Trying to figure out which approach to use in .net/C# to evaluate a simple expression in runtime. Code must be .net standard compliant, and I dont want weird dependecies.
I have looked into using using Microsoft.CodeAnalysis.CSharp.Scripting:
How can I evaluate C# code dynamically? but it seems overkill for my use case.
public class Evaluate
{
private Dictionary<string, object> _exampleVariables = new Dictionary<string, object>
{
{"x", 45},
{"y", 0},
{"z", true}
};
private string _exampleExpression = "x>y || z";
private string _exampleExpression2 = #"if(x>y || z) return 10;else return 20;
";
public object Calculate(Dictionary<string, object> variables, string expression)
{
var result = //Magical code
return result;
}
}
You can try my Matheval library. It can evaluate string expression in pure C# and support IFELSE, SWITCH statement. I don't use any dependencies.
using System;
using org.matheval;
public class Program
{
public static void Main()
{
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
//bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
//eval
Decimal salary = expression.Eval<Decimal>();
Console.WriteLine(salary);
}
}
View my repo at: https://github.com/matheval/expression-evaluator-c-sharp/
In C# you can do this:
class Program
{
private static Func<Dictionary<string, object>, object> function1 = x =>
{
return ((int)x["x"] > (int)x["y"]) || (bool)x["z"];
};
private static Func<Dictionary<string, object>, object> function2 = x =>
{
if (((int)x["x"] > (int)x["y"]) || (bool)x["z"])
{
return 10;
}
else
{
return 20;
}
};
static void Main(string[] args)
{
Dictionary<string, object> exampleVariables = new Dictionary<string, object>
{
{"x", 45},
{"y", 0},
{"z", true}
};
Console.WriteLine(Calculate(exampleVariables, function2));
}
public static object Calculate(Dictionary<string, object> variables, Func<Dictionary<string, object>, object> function)
{
return function(variables);
}
}
I'm pretty new to xUnit and here's what I'd like to achieve:
[Theory]
[InlineData((Config y) => y.Param1)]
[InlineData((Config y) => y.Param2)]
public void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
Basically, I have a GenericConfig object which contains Config and other kind of configurations, but I need to check that every single parameter is valid. Since they're all string, I wanted to simplify using [InlineData] attribute instead of writing N equals tests.
Unfortunately the error I'm getting is "Cannot convert lambda expression to type 'object[]' because it's not a delegate type", which is pretty much clear.
Do you have any idea on how to overcome this?
In addition to the already posted answers. The test cases can be simplified by directly yielding the lambdas.
public class ConfigTestDataProvider
{
public static IEnumerable<object[]> TestCases
{
get
{
yield return new object [] { (Func<Config, object>)((x) => x.Param1) };
yield return new object [] { (Func<Config, object>)((x) => x.Param2) };
}
}
}
This test ConfigTestDataProvider can then directly inject the lambdas.
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(Func<Config, object> func)
{
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
Actually, I was able to find a solution which is a bit better than the one provided by Iqon (thank you!).
Apparently, the InlineData attribute only supports primitive data types. If you need more complex types, you can use the MemberData attribute to feed the unit test with data from a custom data provider.
Here's how I solved the problem:
public class ConfigTestCase
{
public static readonly IReadOnlyDictionary<string, Func<Config, string>> testCases = new Dictionary<string, Func<Config, string>>
{
{ nameof(Config.Param1), (Config x) => x.Param1 },
{ nameof(Config.Param2), (Config x) => x.Param2 }
}
.ToImmutableDictionary();
public static IEnumerable<object[]> TestCases
{
get
{
var items = new List<object[]>();
foreach (var item in testCases)
items.Add(new object[] { item.Key });
return items;
}
}
}
And here's the test method:
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(string currentField)
{
var func = ConfigTestCase.testCases.FirstOrDefault(x => x.Key == currentField).Value;
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
I could maybe come up with something a bit better or cleaner, but for now it works and the code is not duplicated.
I have the problem the same to you, and I found the solution that using TheoryData class and MemberData attribute. Here is the example and I hope the code usefully:
public class FooServiceTest
{
private IFooService _fooService;
private Mock<IFooRepository> _fooRepository;
//dummy data expression
//first parameter is expression
//second parameter is expected
public static TheoryData<Expression<Func<Foo, bool>>, object> dataExpression = new TheoryData<Expression<Func<Foo, bool>>, object>()
{
{ (p) => p.FooName == "Helios", "Helios" },
{ (p) => p.FooDescription == "Helios" && p.FooId == 1, "Helios" },
{ (p) => p.FooId == 2, "Poseidon" },
};
//dummy data source
public static List<Foo> DataTest = new List<Foo>
{
new Foo() { FooId = 1, FooName = "Helios", FooDescription = "Helios Description" },
new Foo() { FooId = 2, FooName = "Poseidon", FooDescription = "Poseidon Description" },
};
//constructor
public FooServiceTest()
{
this._fooRepository = new Mock<IFooRepository>();
this._fooService = new FooService(this._fooRepository.Object);
}
[Theory]
[MemberData(nameof(dataExpression))]
public void Find_Test(Expression<Func<Foo, bool>> expression, object expected)
{
this._fooRepository.Setup(setup => setup.FindAsync(It.IsAny<Expression<Func<Foo, bool>>>()))
.ReturnsAsync(DataTest.Where(expression.Compile()));
var actual = this._fooService.FindAsync(expression).Result;
Assert.Equal(expected, actual.FooName);
}
}
Oddly delegates are not objects, but Actions or Funcs are. To do this, you have to cast the lambda to one of these types.
object o = (Func<Config, string>)((Config y) => y.Param1)
But doing this, your expression is not constant anymore. So this will prevent usage in an Attribute.
There is no way of passing lambdas as attributes.
One possible solution would be to use function calls, instead of attributes. Not as pretty, but could solve your problem without duplicate code:
private void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
[Theory]
public Test1()
{
HasConfiguration((Config y) => y.Param1);
}
[Theory]
public Test2()
{
HasConfiguration((Config y) => y.Param2);
}
public class HrcpDbTests
{
[Theory]
[MemberData(nameof(TestData))]
public void Test(Expression<Func<bool>> exp)
{
// Arrange
// Act
// Assert
}
public static IEnumerable<object[]> TestData
{
get
{
Expression<Func<bool>> mockExp1 = () => 1 == 0;
Expression<Func<bool>> mockExp2 = () => 1 != 2;
return new List<object[]>
{
new object[]
{
mockExp1
},
new object[]
{
mockExp2
}
}
}
}
}
With C#
I want to my delegate method into one dictionary, and put them all out and run.
for example
class class1{
Func<string,int> method1 = new Func<string,int>( x => 3);
Func<int,double> method2 = new Func<string,int>( x => 3.0);
Func<double,bool> method3 = new Func<string,int>( x => true);
Dictionary<string, dynamic> dic = new Dictionary<string, dynamic>();
dic.add("m1",method1)
dic.add("m2",method2)
dic.add("m3",method3)
// rund all method
dynamic RunMethod(Dictionary<string, dynamic> dic , dynamic firstInput, int index = 0)
{
if(index = dic.count) return
RunMethod(dic, dic.ElementAt[index].value(input) , index + 1)
}
void main ()
{
RunMethod( dix , "firstString" )
}
}
(this code has error but expression of what i want to do )
What i want to do is like below.
Create Method 1, 2 ,3
Output type of Method 1 = Input type of Method2 ,
Output type of Method 2 = Input type of Method3
Finally get output of Method3
There is Run Method that take Input that has type of method1 and method dictionary (or list or something)
I want to additional method that check what type of method 1? and output type of method 3
Not sure what are you exactly looking for. This code sample may help you.
class Class1
{
public Func<string, int> method1 = new Func<string, int>(x => 3);
public Func<int, double> method2 = new Func<int, double>(x => 4.0);
public Func<double, bool> method3 = new Func<double, bool>(x => true);
List<Delegate> methodList = new List<Delegate>();
public Class1()
{
methodList.Add(method1);
methodList.Add(method2);
methodList.Add(method3);
}
public object RunMethods(object param)
{
foreach(Delegate del in methodList)
{
param = del.DynamicInvoke(param);
}
return param;
}
}
static void Main(string[] args)
{
Class1 obj = new Class1();
object result = obj.RunMethods("some string");
}
I want to call a different function without write if conditions like this:
if(a==1)
{
function1 ();
}
if(a==2)
{
function2 ();
}
if(a==3)
{
function3 ();
}
I want to call function like this :
Dictionary<int, function> functions= new Dictionary<int, function>();
functions.add(1, function1);functions.add(2, function2);functions.add(3, function3);
function[1];
How can I do this?
It seems your functions are actually actions, since a function returns a value. Also you don't have any method parameters, so you have to use Action.
Dictionary<int, Action> functions= new Dictionary<int, Action>();
functions.Add(1, function1);
functions.Add(2, function2);
functions.Add(3, function3);
function[1](); // <-- calling here needs parentheses
You can do something like the following
void Main()
{
Dictionary<int, Func<bool>> funcMap = new Dictionary<int, Func<bool>>() {
{1, Function1},
{2, Function2}
};
Console.WriteLine(funcMap[1]());
Console.WriteLine(funcMap[2]());
}
// Define other methods and classes here
bool Function1()
{
return true;
}
bool Function2()
{
return false;
}
This works because all functions have the same signature.
You can use lambdas to map functions with different signatures. Idea is the same as with Action:
var functions = new Dictionary<int, Action>
{
{ 1, () => method1(123) },
{ 2, () => method2(123, "123") },
};
functions[1](); // will call method1(123);
where functions are defined like this
void method1(int a) => Console.WriteLine(a);
void method2(int a, string b) => Console.WriteLine(a + b);
Following is my code to convert enum values to Dictionary.
public static Dictionary<string, string> EnumToDictionary<T>() where T : struct, IConvertible
{
var oResult = new Dictionary<string, string>();
if (typeof(T).IsEnum)
foreach (T oItem in Enum.GetValues(typeof(T)))
oResult.Add(oItem.ToString(), oItem.ToString());
return oResult;
}
and this is my enum
public enum MyEnum
{
Value1,
Value2,
value3
}
Currently I am calling that method like
var result=EnumToDictionary<MyEnum>();
but I need to use that method like
var result=MyEnum.EnumToDictionary();
or any other way like string extension methods.
In general your problem is connected with the fact that you want to create a generic extensions method (that's possible) but without any object reference sent as "this" parameter when calling such a method (that's not possible).
So using extension methods is not an option to achieve what you want.
You could do sth like this:
public static Dictionary<string, string> EnumToDictionary(this Enum #enum)
{
var type = #enum.GetType();
return Enum.GetValues(type).Cast<string>().ToDictionary(e => e, e => Enum.GetName(type, e));
}
But this would mean that you need to operate on a certain instance of enum class to call such an extension method.
Or you could do this in such a way:
public static IDictionary<string, string> EnumToDictionary(this Type t)
{
if (t == null) throw new NullReferenceException();
if (!t.IsEnum) throw new InvalidCastException("object is not an Enumeration");
string[] names = Enum.GetNames(t);
Array values = Enum.GetValues(t);
return (from i in Enumerable.Range(0, names.Length)
select new { Key = names[i], Value = (int)values.GetValue(i) })
.ToDictionary(k => k.Key, k => k.Value.ToString());
}
And then call it like this:
var result = typeof(MyEnum).EnumToDictionary();
You could write an extension method, something like:
public static IDictionary<string, string> ToDictionary(this Enum value)
{
var result = new Dictionary<string, string>();
foreach (var item in Enum.GetValues(value.GetType()))
result.Add(Convert.ToInt64(item).ToString(), item.ToString());
return result;
}
But to call such an extension method, you need to provide an instance of the required enum. E.g.
var dict = default(System.DayOfWeek).ToDictionary();