I would like to define the following two functions:
void Map<T>(Func<T, string> mapper);
T Call<T>(string value);
Map needs to store the function that turns a string into a result of type T so that when the "Call" function is called with a type T and a string the appropriate function can be looked up and called.
I was thinking that map could store the function in a dictionary of type Dictionary<Type, Func<object, string>> and then Call could do the casting to the appropriate type but I'm unable to get that to work. Does anyone know how to achieve this?
The first type argument of Func is the input, the second the output: Func<in T, out TResult> -- so you need Func<string, T>.
(The MSDN reference here uses Func<string, string> a fair bit which is annoying.)
Also, the dictionary can't use the type argument T as that's different for each element in the dictionary. Rather, use the superclass of Func<T, TResult> which is Delegate.
This should work:
Dictionary<Type, Delegate> dictionary = new Dictionary<Type, Delegate>();
public void Map<T>(Func<string, T> mapper)
{
dictionary[typeof(T)] = mapper;
}
public T Call<T>(string value)
{
var func = dictionary[typeof(T)] as Func<string, T>;
return func.Invoke(value);
}
You can try and do something like this (there should be a better way, but I can't see it right now):
Dictinary<Type, object> _funcDict = ...;
void Map<T>(Func<T, string>mapper)
{
_funcDict[typeof(T)] = mapper;
}
T Call<T>(string value)
{
var func = (Func<T, string>)_funcDict[typeof(T)]
return func(value);
}
What I don't like, is having an object value type in the dictionary, but I'm not sure how you can avoid it.
Related
I'm having trouble creating dictionary of functions. The issue I'm running against is how to return value from called method.
I tried something like this but it's not working since I get error about returning value from anonymous function. I don't know how to properly invoke lambda since the examples I've seen have no arguments, while I have both input parameters and return value.
private static Dictionary<string, Action<String, String>> dictionary= new Dictionary<string, Action<String, String>>()
{
{"key",
(arg1, arg2) => {
Class instance= new Class();
return instance.MyFunction(arg1, arg2);)
}
}
And I want to call it as
dictionary["key"]("abc", "123");
I know making MyFunction static would be simpler but Class is implementing an interface and I'm working on C# 7.3
You need to use Func , not Action, since Action cannot return a value. The last Type argument to Func is the return type.
private static Dictionary<string, Func<String, String, String>> dictionary =
new Dictionary<string, Func<String, String, String>>()
{
{
"key",
(arg1, arg2) =>
{
Class instance = new Class();
return instance.MyFunction(arg1, arg2);
}
}
};
More information here: https://learn.microsoft.com/en-us/dotnet/api/system.func-2?view=netcore-3.1
You should use Func delegate instead of Action, since it'll return a value (unlike Action) of type specified by last type argument. Assuming that MyFunction returns string, you can declare it like
private static Dictionary<string, Func<string, string,string>> dictionary =
new Dictionary<string, Func<string, string, string>>
{
{
"key",
(arg1, arg2) =>
{
var instance = new Class();
return instance.MyFunction(arg1, arg2);
}
}
};
And invoke like
var result = dictionary["key"]("abc", "123");
You also should fix a typo with an extra bracket in your code.
I'm thinking of creating something like this:
Class.Method<OtherClass>(x => new Dictionary<string, string> { { nameof(x.Property), "Hello World!" } });
I'd like the Method to be void, but somehow I can't get this done. I understand that this signature is
public static void Method<T>(Func<T, Dictionary<string, string>> func)
but I don't want to use the dictionary az a TResult. All I want is to have a dictionary as an input and fill the keys from the T type. Is this possible somehow?
From what I can gather, you're trying to provide a function that populates keys for an existing dictionary. If that's the case, you could do something like this:
public static void Method<T>(Action<T, IDictionary<string, string>> mergeAction);
This can be called like this:
MyClass.Method<OtherClass>((input, dict) => { dict[nameof(input.Property)] = "hello world"; });
A Func<T, TResult> where TResult should return void must be declared as an Action<T>
I am creating a member in a Class which is something like this:
Dictionary<Type, Func<TContract, Task>> ProcessorDictionary = new Dictionary<Type, Func<TContract, Task>>();
In the above Dictionary, I want to maintain bindings between a particular type and its associated processors to be run. I want to enforce a constraint that when you add an entry to this dictionary, TContract should be a instance of "Type". For eg:
Func<MessageContract,Task> func = ...
ProcessorDictionary.Add(typeof(MessageContract), func)
Is this possible? If not what are the alternatives?
It's not possible to really enforce it with something similar to a generic constraint. What you can do is "hide" the dictionary behind a generic method (which does support type constraints).
Simply have a class where the dictionary is private and expose a generic method as such:
private Dictionary<Type, Func<TContract, Task>> _processorDictionary = new Dictionary<Type, Func<TContract, Task>>();
public void AddEntry<TContract>(Func<TContract, Task> func)
{
_processorDictionary[typeof(TContract)] = func;
}
Let's suppose I have defined Func as follows:
Func<MyClass, object> f = o => o.StringProperty;
or
Func<MyClass, object> f = o => o.Property.SomeMethod();
Is there way to get the actual return type without specifically calling it?
You can get the return type like this:
f.Method.ReturnType
But this will return you the type object. If you want to get Method or String or something that derives from object, you won't be able to have the information unless you call the method.
Actually you could, but this would mean that you'd have to dissassemble the method core and then analyze it to see what the method can return. But even then, there might be many different return types.
So the answer is: if you want to know that it returns an object, then yes you can, otherwise it's not worth the trouble, and it's better to find another way of doing what you need.
Since you are retrieving these Func<MyClass, object> delegates at runtime from other sources, the type information is essentially lost.
Instead, where these functions are defined, you can have the callers essentially encode that type information in a wrapped delegate by taking advantage of the LINQ Expression API (EDIT: Silly me, far more simpler at this point; we already have the generic compile time information):
public class MyClassDelegate
{
private readonly Func<MyClass, object> Function;
public Type ReturnType { get; private set; }
private MyClassDelegate(Func<MyClass, object> function, Type returnType)
{
this.Function = function;
this.ReturnType = returnType;
}
public object Invoke(MyClass context)
{
return Function(context);
}
public static MyClassDelegate Create<TReturnType>(Func<MyClass, TReturnType> function)
{
Func<MyClass, object> nonTypedFunction = o => function(o);
return new MyClassDelegate(nonTypedFunction, typeof(TReturnType));
}
}
(A derived generic MyClassDelegate<TReturnType> : MyClassDelegate class could be made as well to get around some of the sillyness in the Create method, or avoid value-type boxing, or to have the return type information available at compile time or even by reflecting on whatever MyClassDelegate<TReturnType> is.)
Callers defining the delegates instead of working directly with a Func<MyClass, object> would instead work with this class and define their delegates as:
MyClassDelegate f1 = MyClassDelegate.Create(o => o.StringProperty);
MyClassDelegate f2 = MyClassDelegate.Create(o => o.Property.SomeMethod());
Your API would require a MyClassDelegate, with which you can easily access their types:
Console.WriteLine(f1.ReturnType.FullName); //string
Console.WriteLine(f2.ReturnType.FullName); //whatever `SomeMethod()` is declared to return
Finally, you can invoke the delegates or even create Func<MyClass, object> delegates still:
f1.Invoke(myClassInstance);
Func<MyClass, object> f3 = f1.Invoke;
You can do something close to this by using a generic method to make the compiler infer the type arguments:
static Func<T1, R> Infer<T1, R>(Func<T1, R> f) { return f; }
And then:
var func = Infer((string s) => s.Length);
This will encode the return type into the type of func at compilation time.
Of course for a more generally applicable solution you would need a bunch of overloads of Infer to cover Action and Func with one, two, three, etc arguments.
If you then want to get the return type at runtime, for any kind of Func it's as simple as func.Method.ReturnType as ppetrov has already pointed out.
I'm trying to write an extension method to insert data into a dictionary of dictionaries defined as follows:
items=Dictionary<long,Dictionary<int,SomeType>>()
What I have so far is:
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1,IDictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)
{
var leafDictionary =
dict.ContainsKey(key1)
? dict[key1]
: (dict[key1] = new Dictionary<TKEY2, TVALUE>());
leafDictionary.Add(key2,value);
}
but the compiler doesn't like it. The statement:
items.LeafDictionaryAdd(longKey, intKey, someTypeValue);
gives me a type inference error.
For the statement:
items.LeafDictionaryAdd<long, int, SomeType>(longKey, intKey, someTypeValue);
I get "...does not contain a definition for... and the best extension method overload has some invalid arguments.
What am I doing wrong?
Some inventive generic usage ;-p
class SomeType { }
static void Main()
{
var items = new Dictionary<long, Dictionary<int, SomeType>>();
items.Add(12345, 123, new SomeType());
}
public static void Add<TOuterKey, TDictionary, TInnerKey, TValue>(
this IDictionary<TOuterKey,TDictionary> data,
TOuterKey outerKey, TInnerKey innerKey, TValue value)
where TDictionary : class, IDictionary<TInnerKey, TValue>, new()
{
TDictionary innerData;
if(!data.TryGetValue(outerKey, out innerData)) {
innerData = new TDictionary();
data.Add(outerKey, innerData);
}
innerData.Add(innerKey, value);
}
Try to use a concrete type:
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)
see the Dictionary<TKEY2,TVALUE> instead of IDictionary<TKEY2,TVALUE>
I'm guessing that this is a covariance / contravariance issue. Your method signature is expecting an IDictionary of IDcitionaries, but you're passing it an IDictionary of Dictionary. Try using a concrete Dictionary instead in your method signature, for the inner Dictionary.
If you specify an IDictionary on your Parameter list for the Extension method,
then your items will not match that.
Either change your Extension to
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(
this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,
TKEY1 key1,
TKEY2 key2,
TVALUE value)
OR Try and cast your items to
((IDictionary<long, IDictionary<int, YourType>>)items).LeafDictionaryAdd(l, i, o);