How to Create a Dictionary of Generic Types

Can I Create a Dictionary of Generic Types?

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.

Creating Dictionaries of generic types

I think you just have to cast it using Cast<T>.

return _fruits[typeof(T)].Values.Cast<T>();

Using a (IEnumerable<T>) to cast does not work because it will cast the whole thing. You may know this already: List<object> can't be casted to List<int>. The same phenomenon happens here.

Therefore, we should use Cast<T>. This method will cast each element of the enumerable to the specified type, and returning the resulting enumerable.

C# Dictionary of generic classes

I tried using boxing/unboxing and came up with this solution. It appears to work... so far. But it doesn't seem very safe.

public interface Variable
{
object getValue();
void setValue(object value);
Type myType();
}

public class Variable<T>: Variable
{
private T myValue;

public object getValue()
{
return myValue;
}

public void setValue(object value)
{
myValue = (T)value;
}

public Type myType() { return myValue.GetType(); }
}

Dictionary<string, Variable> vars = new Dictionary<string, Variable>();

Variable<int> age = new Variable<int>();
age.setValue(21);
vars.Add("age", age);
Variable theAgeVar;
vars.TryGetValue("age", out theAgeVar);
Console.WriteLine("age = " + theAgeVar.getValue());

Variable<double> height = new Variable<double>();
height.setValue(5.9);
Variable theHeightVar;
vars.TryGetValue("age", out theHeightVar);
Debug.Log("height = " + theHeightVar.getValue());

This prints:

age = 21

height = 5.9

One thing I do not like is that I had to make the return type of getValue() be an object. If I wanted myValue (which is of type T) to implement IComparable, for instance, then this information is lost when the boxing happens and the caller receives an object.

Dictionary of generic lists or varying types

How about Dictionary<string, dynamic> assuming you're on C# 4

Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Dict.Add("int", new List<int>());
Dict.Add("string", new List<string>());

Dict["int"].Add(12);
Dict["string"].Add("str");

foreach (KeyValuePair<string, dynamic> pair in Dict) {
Type T = pair.Value.GetType();
Console.WriteLine(T.GetGenericArguments()[0].ToString());
}

That prints out

System.Int32

System.String

Is that what you're looking for?

C# - Define a dictionary of generic functions

Try this class:

public class Stringifier
{
private Dictionary<Type, Delegate> _store
= new Dictionary<Type, Delegate>();

public void Store<T>(Func<T, string> value)
{
_store[typeof(T)] = value;
}

public Func<T, string> Fetch<T>()
{
return (Func<T, string>)_store[typeof(T)];
}

public string Fetch<T>(T value)
{
return this.Fetch<T>().Invoke(value);
}

public string Fetch(Type type, object value)
{
return (string)
(
typeof(Stringifier)
.GetMethods()
.Where(x => x.Name == "Fetch")
.Where(x => x.IsGenericMethod)
.Where(x => x.ReturnType == typeof(string))
.Select(x => x.MakeGenericMethod(type))
.First()
.Invoke(this, new [] { value })
);
}
}

Then you can do this:

var stringifier = new Stringifier();

stringifier.Store<string>(s => $"!{s}!");
stringifier.Store<float>(f => f.ToString());
stringifier.Store<bool>(b => b.ToString());

var bar = "XXX";

var value = stringifier.Fetch(bar.GetType(), bar);

Console.WriteLine(value);

The output I get is !XXX!.

Generic type struct in dictionary

If you want your dictionary to be type specific:

private Dictionary<string, Command<my_type>> _commandMap;

If you want everything in one dictionary, then don't use a generic for the class.

You wrote, that you want to store a class type property to instantiate it later. Yet in your code you store a class instance, not a class type.

I think this is what you are looking for:

internal struct Command
{
internal string trigger;
internal Type clazz;
internal string category;
}

or

internal struct Command
{
internal string trigger;
internal IMyInterface clazz;
internal string category;
}

and finally:

private Dictionary<string, Command> _commandMap;

Infer Generic type in dictionary property

The type you're looking for is a dictionary where each entry is some IMyInterface<T> type, but not any particular T. This is probably best expressed as an existential type like (possibly) {[k: string]: IMyInterface<exists T>}, which isn't currently supported natively in TypeScript (nor most other languages with generics). TypeScript (and most other languages with generics) only has universal types: someone who wants a value of type X<T> can specify any type for T that they want, and the provider of the value must be able to comply. An existential type is the opposite: someone who wants to provide a value of a type like X<exists T> can choose any specific type for T that they want, and the receiver of that value just has to comply. Existential types let you "hide" the generic type inside a non-generic type.

But, TypeScript doesn't have existential types, so we'll have to do something else. (Well, it doesn't have native existential types. You can emulate them by using generic functions and inverting control via callbacks, but that's even more complicated to use than the solution I'm going to suggest next. If you're still interested in existentials you can read the linked article about it)


The next best thing we can do is to describe the shape of IMyDictionary as a generic type, where we don't really care about it, and get the compiler to infer it for us as much as possible. Here's one way:

type IMyDictionary<T> = { [K in keyof T]: IMyInterface<T[K]> }
const asIMyDictionary = <T>(d: IMyDictionary<T>) => d;

The idea is that instead of declaring a variable to be of type IMyDictionary, you use the helper function asIMyDictionary() to take the value and produce a suitable type IMyDictionary<T>. This only works, by the way, because the type IMyDictionary<T> is a homomorphic mapped type, so T can be inferred from a value of type IMyDictionary<T>. Let's see it in action:

const myDictionary = asIMyDictionary({
test1: {
propA: { name: "John", age: 18 },
propB: { age: 40 }
},
test2: {
propA: { size: 10, color: "blue" },
propB: { color: "purple" }
},
test3: {
propA: { problem: true },
propB: { oops: false } // error!
// ~~~~~~~~~~~~
// 'oops' does not exist in type '{ problem?: boolean | undefined; }'
}
});

This works and gives you errors where you expect them. Yay!

The caveat here is you still have to drag around this T type you don't care about. Any function or type which you were hoping would just deal with a concrete IMyDictionary will have to become generic. Maybe that's not too painful to you. If it is, you can think about the "emulated" existential type. But I've already written a lot here, so hopefully the above will help you... if you need me to write out the emulated existential version, I can.

Good luck!

Create a dictionary of generic variables in swift

variable1 and variable2 are not of type Entity but are in fact Entity<Float> and Entity<String> which are two unrelated types. Use a protocol to unite them:

protocol EntityProtocol { }

class Entity<T> : EntityProtocol {
var _value: T
var value: T { get { return _value } set {_value = newValue}}

init (defaultValue: T) {
_value = defaultValue
}
}

class FloatEntity: Entity<Float> {
}

class StringEntity: Entity<String> {
}

func run () {
let variable1: Entity = FloatEntity (defaultValue: 1)
let variable2: Entity = StringEntity (defaultValue: "")
var dictionary: Dictionary<String, EntityProtocol> = [
"One": FloatEntity (defaultValue: 1),
"Two": StringEntity (defaultValue: ""),
]
print (variable1)
print (variable2)
print (dictionary)
}


Related Topics



Leave a reply



Submit