I want to put Func where T is a generic type as values in a dictionary. So Basically I want to do something like:
Dictionary<string, Func<MyObject, T>> _sortMappings =
new Dictionary<string, Func<MyObject, T>>()
{
{ "Name", (b) => b.Name }, // name is a string
{ "Length", (b) => b.Length }, // length is an int
{ "Date", (b) => b.Date } // a datetime object
};
Does this make sense and is this possible?
It is not possible with Func<MyObject, T> you need to use Func<MyObject, object>. T can't be more than one type at the same time. So you need to find a common type for string, int and DateTime which is object.
try in this way using Convert.ChangeType Method
"Name", b => (T)System.Convert.ChangeType(b.Name,typeof(T))
your function should be
private static T InvokeFunction<T>(Func<T> func)
{
Dictionary<string, Func<MyObject, T>> sortMappings =
new Dictionary<string, Func<MyObject, T>>();
sortMappings.Add("Name", b => (T)System.Convert.ChangeType(b.Name,typeof(T)));
sortMappings.Add("Length", b => (T)System.Convert.ChangeType(b.Length, typeof(T)));
sortMappings.Add("Date", b => (T)System.Convert.ChangeType(b.Date, typeof(T)));
return func.Invoke();
}
Related
I would like to pass an expression that represents a variable to used when instantiating an object.
Instead of:
class MyObject : IMyInterface { ... }
var list = db.MyObjects.Where(x => !x.IsDeleted).ToList();
var anotherList = list.Select(x => new AnotherObject() {
Id = x.Id,
Value = x.Value
});
I would like to make this so that a list of objects of IMyInterface can be transformed into another type of list (AnotherObject as example) using defined expressions as so:
var list = db.MyObjects
.Where(x => !x.IsDeleted)
.ToAnotherObjectList(x => x.Id, x => x.Value);
...
public static List<AnotherObject> ToAnotherObjectList<T>(
this IEnumerable<IMyInterface> list,
Expression id,
Expression value)
{
return list.Select(x => new AnotherObject() { Id = id, Value = value }).ToList();
}
I'm not sure how to accomplish this. I know I can use reflection to create objects and set properties by a string but I'm not sure how to pass expressions.
UPDATE
Well, I thought I'd have to do some reflection but it's simpler than what I was thinking. Here's my solution that works in IRL.
public static IEnumerable<AnotherObject> ToAnotherObject<T>(this IEnumerable<T> list, Func<T, int> getId, Func<T, string> getValue, Func<T, bool> getSelected = null) where T : IMyInterface
{
return list.Select(x => new AnotherObject {
Display = getValue(x),
Id = getId(x),
Selected = getSelected != null && getSelected(x),
});
}
You could use a Func<TInput,TReturn> for that. For example:
public static List<AnotherObject> ToAnotherObjectList<T>(
this IEnumerable<T> list,
Func<T, int> getId,
Func<T, object> getValue)
{
return list.Select(x => new AnotherObject() { Id = getId(x), Value = getValue(x) }).ToList();
}
Call:
list.ToAnotherObjectList(i => i.Id, i=> i.Value);
In this example I used Funcs with one parameter (of type T) and return type int/object.
The method MyMethod as a string parameter. Based on the value of this parameter, I'd like get back an expression to use with an OrderBy. I don't find the right syntax for Expression<Func<>> to use with the dictionary (as TValue type)
public void MyMethod(string orderBy)
{
var dico = new Dictionary<string, string>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
dico.TryGetValue("property1", out string myOrder);
myList.OrderBy(myOrder)......
}
Update :
var dico = new Dictionary<string, Expression<Func<Person, xxxxx>>>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
Thanks,
I think you may get hints from this:
public void MyMethod(string orderBy)
{
// Assuming Product has 'Name' and 'Age' property ?
var dico = new Dictionary<string, Expression<Func<Product,object>>>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
Expression<Func<Product,object>> myorder;
dico.TryGetValue(orderBy, out myOrder);
_context.Products.OrderBy(myOrder);
}
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!
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();
I have an IEnumberable> and I want only the list of Keys but cast to the needed type (i.e. perhaps short and not int). This is used in a custom generic multi-select control the binds to but the database needs potientially 'short' to save.
public static IEnumerable<T> GetKeysOnly<T>(this IEnumerable<KeyValuePair<int, string>> values)
{
Dictionary<int, string> valuesDictionary = values.ToDictionary(i => i.Key, i => i.Value);
List<int> keyList = new List<int>(valuesDictionary.Keys);
// Returns 0 records cuz nothing matches
//List<T> results = keyList.OfType<T>().ToList();
// Throws exception cuz unable to cast any items
//List<T> results = keyList.Cast<T>().ToList();
// Doesn't compile - can't convert int to T here: (T)i
//List<T> results = keyList.ConvertAll<T>(delegate(int i) { return (T)i; });
throw new NotImplementedException();
}
public static IEnumerable<short> GetKeysOnly(this IEnumerable<KeyValuePair<int, string>> values)
{
Dictionary<int, string> valuesDictionary = values.ToDictionary(i => i.Key, i => i.Value);
List<int> keyList = new List<int>(valuesDictionary.Keys);
// Works but not flexable and requires extension method for each type
List<short> results = keyList.ConvertAll(i => (short)i);
return results;
}
Any advice how to make my generic extension method work?
Thanks!
You want to get only the keys converted to a short?
var myList = valuesDictionary.Select(x => (short)x.Key).ToList();
// A Dictionary can be enumerated like a List<KeyValuePair<TKey, TValue>>
If you want to go to any type, then you would do something like this:
public static IEnumerable<T> ConvertKeysTo<T>(this IEnumerable<KeyValuePair<int, string>> source)
{
return source.Select(x => (T)Convert.ChangeType(x.Key, typeof(T)));
// Will throw an exception if x.Key cannot be converted to typeof(T)!
}