I want to create a list of actions to perform on a drawing object. Here's what the non-generic code would look like:
private Dictionary<String, Action<Drawing, String>> actions = new Dictionary<String, Action<Drawing, String>>();
private void LoadActions()
{
actions.Add("Height", (d, s) => d.Height = Double.Parse(s));
actions.Add("Width", (d, s) => d.Width = Double.Parse(s));
}
private void ProcessDrawing(Drawing drawing, String prop, String value)
{
actions[prop](drawing, value);
}
The problem I have is that the Drawing class is a generic one (Drawing<T>) so I can't define actions like the following because T is not defined:
Dictionary<String, Action<Drawing<T>, String>> actions = new Dictionary<String, Action<Drawing<T>, String>>();
Without caching the code looks like this:
private void ProcessDrawing<T>(Drawing<T> drawing, String prop, String value)
{
var actions = new Dictionary<String, Action<Drawing<T>, String>>();
actions.Add("Height", (d, s) => d.Height = Double.Parse(s));
actions.Add("Width", (d, s) => d.Width = Double.Parse(s));
actions[prop](drawing, value);
}
So how can I cache a bunch of actions accepting a generic type of parameter?
Thanks,
The base class of all Actions is MulticastDelegate. You would have to define your dict as Dictionary<String,MulticastDelegate> and use appropriate castings after retrieving your actions from the dict.
EDIT:
Tests show that lambda expressions can obviously not be directly assigned to variables of type MulticastDelegate. This is because the type of the lambda expression parameters is inferred from the type of the variable (or method parameter) it is assigned to. Therefore assign it first to a variable with the right Action<> type. Then assign this to MulticastDelegate.
In the example, I show both versions (through a method parameter and through a variable):
public static void CallTestDelegate()
{
TestDelegate((d, s) => d.Height = Single.Parse(s));
}
public static void TestDelegate(Action<RectangleF, string> action)
{
Dictionary<String, MulticastDelegate> dict = new Dictionary<string, MulticastDelegate>();
dict.Add("a1", action);
Action<RectangleF, string> action2 = (d, s) => d.Width = Single.Parse(s);
dict.Add("a2", action2);
var a1 = (Action<RectangleF, string>)dict["a1"];
a1(new RectangleF(), "15");
}
One option is to make Drawing<T> derive from a non-generic interface IDrawing that has Height and Width properties, then change your actions to be of type Action<IDrawing,String>.
Another option (less type-safe) is to make your actions of type Action<dynamic,String>.
T is just a placeholder, make an abstract class or interface representing objects that you want
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.
Is it possible in C# to get a reference to a member function without specifying the object, so that it is usable like a static extension method, taking the object as first parameter?
class Handler
{
public void Add(int value) { ... }
}
static class HandlerExtensions
{
public static void AddEx(this Handler instance, int value) { ... }
}
var x = new Handler();
// possible:
Action<int> func1 = x.Add;
Action<Handler, int> func2 = HandlerExtensions.AddEx;
// not possible?
Action<Handler, int> func3 = Handler::Add;
Why would I want to do that? To specify methods to call in a class before having an actual object to work with:
// current solution:
void RegisterDto<DataType>(Func<Handler, Action<DataType>> handler) { ... }
RegisterDto<int>(x => x.Add);
// desired solution:
void RegisterDto<DataType>(Action<Handler, DataType> handler) { ... }
RegisterDto<int>(Handler::Add); // <--- does syntax for this exist?
If you mean "can you create a delegate like that" then the answer is "yes, but it's slightly ugly". I don't think you can use a method group conversion, but you can use reflection and Delegate.CreateDelegate, e.g.
MethodInfo method = typeof(Handler).GetMethod("Add");
var action = (Action<Handler, int>)
Delegate.CreateDelegate(typeof(Action<Handler, int>), method);
It would be nice to have a method group conversion here, I agree.
This might not work for you use-case, but you can create a delegate with
Action<Handler, int> f = (h, v) => h.Add(v);
And to use it
var handler = new Handler();
f(handler, 100);
If you don't want to evaluate it each time, maybe you could make it Lazy
Func<Lazy<Handler>, Action<int>> addMethod = target => target.Value.Add;
// example of usage
var lazyHandler = new Lazy<Handler>();
Test(addMethod(lazyHandler), 1);
I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}
I have a GenericListItem object that has a Text and ID property. I am casting various DB objects into List for the purpose of binding to simple generic list controls.
I would like to write an extension method on List that would allow me to specify the relevant properties of T that would get mapped to the Text and ID properties of GenericListItem and then be able to easily convert any List to a list
The signature for the method would need to then somehow accept the two properties of T so I can then output from the list a new List
is something like this possible?
I'd create an extension method to convert items, and use that to convert the lists:
public static GenericListItem ToListItem<T>(this T obj, Func<T, string> textFunc, Func<T, int> idFunc)
{
return new GenericListItem
{
Text = textFunc(obj),
Id = idFunc(obj)
};
}
public static List<GenericListItem> ToItemList<T>(this IEnumerable<T> seq, Func<T, string> textFunc, Func<T, int> idFunc)
{
return seq.Select(i => i.ToListItem(textFunc, idFunc)).ToList();
}
Instead of reinventing the wheel, you can use Linq:
List<string> list = new List<string>();
list.Add("first");
list.Add("second");
List<ListItem> items = list.Select(s => new ListItem() {Id = s.Length, Text = s.ToLower()}).ToList();
// or if ListItem has a constructor with parameters
List<ListItem> items = list.Select(s => new ListItem(s.Length, s.ToLower()).ToList();
If you really insist on extension, you can wrap the above logic into an extension method, but I don't see the point:
List<ListItem> items = list.ToItemList(s => s.Length, s => s.ToLower());
static class Helper
{
public static List<ListItem> ToItemList<T>(this IList<T> list, Func<T, int> idFunc, Func<T,string> textFunc)
{
return list.Select(s => new ListItem() { Id = idFunc(s), Text = textFunc(s) }).ToList();
}
}
Whatever you choose, don't write a method where you specify properties by name. When you change the name of the properties, compiler will not be able to show you that you have forgotten to update the names in calls to your method, because they are just strings.
public class customList<T> : IList<T>
{
public List<GenericListItem> ToCustomListItem()
{
List<GenericListItem> listItems = new List<GenericListItem>();
//logic to convert list to GenericListItem
}
}
to use do the following
customList<object> list = new customList<object>();
//populate your list
list.ToCustomListItem();
But yes, you can change the names and types as you need to.
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.