C# reflection dictionary - c#

say I have this code:
Dictionary<String, String> myDictionary = new Dictionary<String, String>();
Type[] arguments = myDictionary.GetType().GetGenericArguments();
In my program, myDictionary it's of unknown types (it's an object returned from a deserialized XML), but for the purpose of this question, they are string. I want to create something like this:
Dictionary<arguments[0],arguments[1]> mySecondDictionary = new Dictionary<arguments[0],arguments[1]>();
Obviously, it doesn't work.
I searched on MSDN, and I saw they are using the Activator class, but I don't get it.
Maybe somebody more advanced, could help me a little.

You can use the activator class like you mentioned in order to create objects from given types. The MakeGenericType method allows you to specify an array of Types as the parameters for generic objects, which is what you were trying to simulate.
Dictionary<String, String> myDictionary = new Dictionary<String, String>();
Type[] arguments = myDictionary.GetType().GetGenericArguments();
Type dictToCreate = typeof(Dictionary<,>).MakeGenericType(arguments);
var mySecondDictionary = Activator.CreateInstance(dictToCreate);
The code above is essentially pointless as you know that the dictionary is String,String beforehand but assuming you have a way of detecting the required types elsewhere during runtime, you can use the last two lines to instantiate a dictionary of that type.

There is a problem with this approach.
I will try my best to explain it.
I wrote a program which first serializes a class into XML, then deserializes it back.
Basically, the class it's a generic one, and it contains a List(the same type with the class).
So, the type of the class could be anything, starting from simple types, like string, int, etc to more complex classes, like for example a book class, or a person. After using the XmlSerializer.Deserialize method, and getting the object, I should use Reflection to reconstruct back the object, and access the list. And I can't do it that way.
So, if I have something like:
Type classToCreate = typeof(classToBeSerialized<>).MakeGenericType(arguments);
var reconstructedClass = Activator.CreateInstance(classToCreate);
where classToBeSerialized it's the supposed class(which has the list which I have spoken of), and returnedObject it's the object returned from XmlSerializer.Deserialize, I want to access the list like this:
((reconstructedClass)returnedObject).lista
Basically, I'm using reflection to cast the object to it's source.

I know this is an old thread, but I just needed something similar, and decided to show it, (you know for google).
this is basicly a rewrite of the answer by #user2536272
public object ConstructDictionary(Type KeyType, Type ValueType)
{
Type[] TemplateTypes = new Type[]{KeyType, ValueType};
Type DictionaryType = typeof(Dictionary<,>).MakeGenericType(TemplateTypes);
return Activator.CreateInstance(DictionaryType);
}
public void AddToDictionary(object DictionaryObject, object KeyObject, object ValueObject )
{
Type DictionaryType = DictionaryObject.GetType();
if (!(DictionaryType .IsGenericType && DictionaryType .GetGenericTypeDefinition() == typeof(Dictionary<,>)))
throw new Exception("sorry object is not a dictionary");
Type[] TemplateTypes = DictionaryType.GetGenericArguments();
var add = DictionaryType.GetMethod("Add", new[] { TemplateTypes[0], TemplateTypes[1] });
add.Invoke(DictionaryObject, new object[] { KeyObject, ValueObject });
}

Related

Using a Dictionary<string, Type> to use the value as type of a list

I am trying to build a solution fitting with the problem of not knowing what kind of Setting type I am dealing with.
I got a Dictionary<string, Type> (which I initially wanted to make <string, class> but that didn't work)
that I want to fill with the setting code and the type of class attached to it i.e.
{ "person_customField", typeof(CustomFieldModel) }
Why I want to do this is because I have a field in my database filled with json data that should be deserialized to a List<> but I don't know what kind of setting it is until I get the object from the database. I can use the Code field to detemine what type it is (person_CustomField should use the CustomFieldModel class, but emailSetting should use EmailSettingModel to match parameters to.
Is there a way to successfully make this statement work with?
JsonConvert.DeserializeObject<List<SettingTypes[record.SettingCode]>>(record.SettingValues).ToList<ISetting>()
Or should I go a different route
Code Sample:
public static readonly Dictionary<string, Type> SettingTypes = new Dictionary<string, Type>()
{
{ "person_CustomFields", typeof(CustomFieldModel)},
};
public static TenantSettingEdit ConvertToTenantSettingEdit(this T_TenantSetting rec)
{
var test = SettingTypes[rec.TENS_Code];
TenantSettingEdit item = new TenantSettingEdit()
{
IDToken = rec.TENS_TenantSettingID.toVirtualGuid().ToString(),
Code = rec.TENS_Code,
Settings = JsonConvert.DeserializeObject<List<SettingTypes[rec.TENS_Code]>>(rec.TENS_Setting).ToList<ITenantSetting>(),
IsActive = rec.TENS_ActiveRec,
};
return item;
}
(I have done this before with PHP but I am not sure if this is even remotely possible with C#)
Why I want to do this is because I have a field in my database filled
with json data that should be deserialized to a List<> but I don't
know what kind of setting it is until I get the object from the
database.
If you're using Json.Net for JSON serialization/deserialization you can use the TypeNameHandling property to embed Type information in the resulting JSON. That JSON can the be deserialized by Json.Net without additional information. If it is necessary to map custom values to the types instead of the automatically generated ones you can use a SerializationBinder (check out this answer).
If none of those help you, you can still fall back to reflection in the way M Kloster describes.
You cannot use a variable as the type parameter in the code, no. What you need to do is to generate the type-specific method by reflection:
var genericMethod = ((Func<string, int>)Json.DeserializeObject<int>).Method.GetGenericMethodDefinition();
var boundMethod = genericMethod.MakeGenericMethod(SettingTypes[record.SettingCode]);
var result = boundMethod.Invoke(null, rec.TENS_Setting)...

Create list of generic object at runtime

I have object of some type known at runtime and I read and deserialize this object from database. It works. Now I would like to add it to some list:
private static List<T> generateList<T>()
{
List<T> lst = new List<T>();
return lst;
}
private void readObjects(System.Type objType)
{
var methodInfo = typeof(My.Serializator).GetMethod("DeserializeDb");
var genericMethod = methodInfo.MakeGenericMethod(objType1);
List<curType> currentList= generateList<curType>();
// ...read stream from database and convert it to object
while (_rs.Read())
{
var _objItem = genericMethod.Invoke(null, new[] { _streamedData });
currentList.Add(_objItem);
}
}
It won't work. The error is:
curType is a variable but is used like a type.
If I change list to:
List<object> currentList = new List<object>();
it will work. But can i do this with generics(T) instead of object type?
You can easly create type of list you want via Activator, then cast to IList and use it:
private IList readObjects(System.Type objType)
{
var listType = typeof(List<>).MakeGenericType(curType);
var list = (IList)Activator.CreateInstance(listType);
// ...
while (_rs.Read())
{
// ...
list.Add(_objItem);
}
}
list will be instance of List<YorActualType>.
Update
When you declaring your method with generic arguments, it assumes you provide type info during compile time. Otherwise you need to use reflection.
Since you providing type info in run time (curType can hold any type info), compiler does not know what exactly type will be used, and you cannot declare your method to return something concrete. Only abstractions allowed.
Let's me show it on slightly insane but demonstrative example:
var types = new [] { typeof(int), typeof(string) };
var rand = new Random();
var list = readObjects(types[rand.Next(0,2)];
Until the very last moment even you will not know what exactly type of list will be created. Compiler does not know too. Compiler will never know what exactly type should be used if you not provide him with you types. When you use Type it only tells compiler that some regular parameter with type Type will be passed into the method in run time. There is no data to infer a type during compile time. That data can be passed only via generic type parameters.
So, there is several ways you can follow:
Provide exact types you need at compile time
private List<T> readObjects<T>()
{
var objType = typeof(T);
var list = new List<T>();
// rest of code....
}
Use reflection and base types
private IList readObjects(Type objType)
{
// rest of code with Activator and so on
}
And later usage depends on your needs.
If you know what type you going to use, simply convert:
var list = (IList<MyType>)readObjects(typeof(myType));
But I guess in that case better use way #1 with generic argument.
Otherwise you going to use reflection. Or some base classes, interfaces and so on. It depends on what exactly task you going to solve.
P.S. You can read more about generic types on MSDN.

C#, instantiating a generic type - with variable type argument?

Code example:
void Foo(params object[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
var entry = new Entry<o.GetType()>(); // this doesn't work
entries.Add(entry);
}
...
}
Foo("hello", 5); // should fill entries with Entry<string> and Entry<int>
Why is that not possible? I guess I need to work with reflection instead? How to do that properly AND performant?
You just can't use C# generics the way you're trying to do in your snippet.
In order to use [C#] generics, the actual object type must be known at compile time.
You're trying to dynamically pass the object type as a type parameter. This is simply not possible.
Edit
Yes, it is possible to dynamically create generic objects using reflection. After all, generics is implemented both as a compile-time C# construct and as a .NET framework feature (as opposed to, say, Java, where it is only a compile-time feature based on Type Erasure). So, in .NET, through reflection, it is possible to implement the latter "bypassing" the former (which, again, would be impossible in Java).
But the OP clearly does not need that.
After all, entries is a List<IEntry>. IOW, the entries container does not "know" the concrete type of its elements (since it is bound to an interface). So, if each element to be add already implements IEntry, then this would be enough:
void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
OTOH, if those objects do not implement IEntry, then the OP just need a pure, ordinary, old-school list of untyped objects:
void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
So using reflection in order to dynamically create a generic container, even if possible, seems to be overkill for this particular use case.
You can do it with reflection
var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
You need a function of the form:
Func<Type, IEntry>
I would suggest adding a static function to the parent of Foo like this:
public static IEntry Make(Type type)
Inside that function, feel free to add whatever code makes sense to you:
if (type == typeof(string))
{
return new StringEntry(); //Obviously some special logic based on the type.
}
else
{
//Default logic
return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type));
}

How can I pass a type, rather than an instance, to a function in C#?

I am attempting to use reflection to enumerate class fields and methods in order to do some automation in a web application. I am also abstracting this so that I could pass in any class.
Is there a way I could somehow pass in the type directly to a function to enumerate on rather than an instance of the type?
I would like the caller side to look like this:
var m = new MyClass(AClassOfSomeTypeIDefined);
I would like to avoid creating an instance as that is misleading to anyone who might use the class (as the instance isn't directly used).
using System;
public void UseType(Type t) {
// do something with t using reflection techniques - e.g.
Console.WriteLine("compat with int? {0}", typeof(int).IsAssignableFrom(t));
}
Call it with C# typeof keyword and the data type you want to pass.
// Examples...
UseType( typeof(int) );
UseType( typeof(System.Int32) );
UseType( typeof(System.Windows.Controls.Button) );
UseType( typeof(IDisposable) );
UseType( typeof(WhateverTypeYouWant) );
System.Type is one of the cornerstones of reflection as you already know, so run with it.
Other notes
Depending on what you want to do with the type, the following peripheral details might be useful.
To create an instance of a Type at runtime without having used the new keyword at compile time, use the System.Activator class. e.g.
// Create a List of strings like: new List<string>();
var list = (List<string>) Activator.CreateInstance( typeof(List<string>) );
yes just use the Type of your class. There's two basic ways to get the type:
Foo foo = new Foo();
Type myType = foo.GetType();
Type myTyp2 = typeof(Foo);
You can use GetType() if you only know the type at runtime (more common with reflection), or typeof() if you know the type at compile time already.
In your example this would be i.e.
var m = new MyClass(typeof(Foo));
You can pass a Type object just like any other parameter.
class MyClass
{
public MyClass(Type yourType)
{
// do as you please with yourType
}
}
The call it:
var m = new MyClass(typeof(YourType));

How to dynamcially call a generic method based on a mapping in a dictionary?

I have a method
String Foo<T> where T: WebControl
Now I do have a string like "hyperlink". What is want is to call Foo<Hyperlink> based on a mapping from the string to the generic.
How does the dictionary have to look like?
It ain't:
private Dictionary<string, Type> _mapping = new Dictionary<string, Type>()
{
{"hyperlink", typeof(HyperLink)}
};
I want to access it like Foo<_mapping[mystring]> is that possible? If yes, how must be dictionary look like?
Edit: Accepted Solution
String _typename = "hyperlink";
MethodInfo _mi = typeof(ParserBase).GetMethod("Foo");
Type _type = _mapping[_typename];
MethodInfo _mig = _mi.MakeGenericMethod(_type);
return (String)_mig.Invoke(this, new object[] { _props }); // where _props is a dictionary defined elsewhere
// note that the first parameter for invoke is "this", due to my method Foo is not static
What you want isn't possible, as that would be runtime (e.g. the dictionary could contain anything later).
If you want to manually generate it via runtime, you can do so, but you won't get the compile-time checking C# has on generics. You can to this via MethodInfo.MakeGenericMethod.
Like this:
var m = typeof(MyClass);
var mi = ex.GetMethod("Foo");
var mig = mi.MakeGenericMethod(_mapping["hyperlink"]);
//Invoke it
mig .Invoke(null, args);
It isn't possible this way. Generics supports only compile-tipe binding.
No, you can't do that. Your generic type wants to create itself at compile time but it doesn't know what type it is til runtime. You can, however, use reflection.
Type untypedGeneric = typeof(Foo<>);
Type typedGeneric = untypedGeneric.MakeGenericType(_mapping[mystring]);

Categories

Resources