when i run the program an error message pops up, it says: Object reference not set to an instance of an object from the methodinfo.invoke(data, null). what i want is create a dynamic generic collection in run time, depends on the xml file, it can be list<classname>, dictionary<string, classname>, customgenericlist<T>, etc.
Below are the codes: using list as a test subject.
data = InstantiateGeneric("System.Collections.Generic.List`1", "System.String");
anobj = Type.GetType("System.Collections.Generic.List`1").MakeGenericType(Type.GetType("System.String"));
MethodInfo mymethodinfo = anobj.GetMethod("Count");
Console.WriteLine(mymethodinfo.Invoke(data, null));
this is the code to instantiate the said datatype:
public object InstantiateGeneric(string namespaceName_className, string generic_namespaceName_className)
{
Type genericType = Type.GetType(namespaceName_className);
Type[] typeArgs = {Type.GetType(generic_namespaceName_className)};
Type obj = genericType.MakeGenericType(typeArgs);
return Activator.CreateInstance(obj);
}
Count is a property, not a method:
var prop = anobj.GetProperty("Count");
Console.WriteLine(prop.GetValue(data, null));
However, it would be better to cast to the non-generic IList:
var data = (IList)InstantiateGeneric("System.Collections.Generic.List`1",
"System.String");
Console.WriteLine(data.Count);
I also suggest talking in terms of Type, not magic strings:
var itemType = typeof(string); // from somewhere, perhaps external
var listType = typeof(List<>).MakeGenericType(itemType);
var data = (IList)Activator.CreateInstance(listType);
Console.WriteLine(data.Count);
Related
I would like to know if it is possible to create an instance of a type known only at runtime and assign values to the properties of this instance by using compiled expressions and if so how it is to be done.
I have a generic class with a method which accepts an instance of T and returns a copy. T is only known at runtime or rather is user/consumer defined. I know how to do so with reflection (assuming it has an empty constructor in this example and without exception handling or null checks for simplification).
public class MyClass<T>
{
public T CreateCopy(T source)
{
var type = typeof(T);
var copy = type.GetConstructor(Type.EmptyTypes).Invoke(null);
foreach(var pi in type.GetProperties())
{
pi.SetValue(copy, pi.GetValue(source));
}
return copy;
}
}
Reflection is quite expensive and after some digging i found an option to at least create an instance of T with compiled expressions.
var type = typeof(T);
Expression.Lambda<Func<T>>(Expression
.New(type.GetConstructor(Type.EmptyTypes)
?? throw new InvalidOperationException(
$"Type has to have an empty public constructor. {type.Name}")))
.Compile();
After some benchmarking i have found out that it performs around 6 times faster than the CreateCopy(...) method. The thing is that i do not know which type will be passed in as a generic and how many properties it will have.
Is there a way to do all of the operations from CreateCopy(...) method with compiled expressions?
Ihave looked into Expression.Asign, Expression.MemberInit but i am not able to find anything appropriate. The problem with Expression.MemberInit ist that it expects to have an Expresssion.Bind and Expression.Constant but i cant get the values of the properties from the passed instance of T into it. Is there a way?
Thank you.
P.S. So i am looking for something like:
var type = typeof(T);
var propertyInfos = type.GetProperties();
var ctor = Expression.New(type.GetConstructor(Type.EmptyTypes));
var e = Expression.Lambda<Func<T, T>>(Expression
.MemberInit(ctor, propertyInfos.Select(pi =>
Expression.Bind(pi, Expression.Constant(pi.GetValue(source)))))).Compile();
You are almost there. What you need is to define a parameter and then assign the properties with property access expression like below :
public static T Express<T>(T source)
{
var parameter = Expression.Parameter(typeof(T), "source");
var type = typeof(T);
var ctor = Expression
.New(type.GetConstructor(Type.EmptyTypes));
var propertyInfos = type.GetProperties();
var e = Expression
.Lambda<Func<T, T>>(
Expression
.MemberInit(ctor, propertyInfos.Select(pi =>
Expression.Bind(pi, CanBeAssigned(pi.PropertyType)
? (Expression)Expression.Property(parameter, pi.Name)
: Expression.Call(typeof(Program).GetMethod(nameof(Express))
.MakeGenericMethod(pi.PropertyType),
Expression.Property(parameter, pi.Name)
))
)),
parameter
);
var x = e.Compile();
var z = x(source);
return z;
}
public static bool CanBeAssigned(Type t)
{
return t.IsValueType || t.Name == "String"; // this might need some improvements
}
I have a class VResult<T> that can be instantiated with
bool value = true;
VResult<bool> vr = new VResult<bool>(value);
If I don't know the type of value, I'd like to do something like
VResult<typeof value> = new VResult<typeof value>(value);
Is that possible?
The ultimate goal is to serialize/deserialize VResult<T>:
string json = JsonConvert.SerializeObject(new VResult<bool>(true));
where could be an object or basic datatype such as int or bool.
I'm using a data transfer object that adds
ValueTypeName = Value.GetType().Name;
and
ValueTypeNamespace = Value.GetType().Namespace;
properties so that on the receiving side I can use
JObject obj = JObject.Parse(json);
string vt = (string)obj["ValueTypeName"];
string vtn = (string)obj["ValueTypeNamespace"];
Type type = Type.GetType($"{vtn}.{vt}");
var value = Activator.CreateInstance(type);
value = obj["Value"];
VResult<typeof value> vr = new VResult<typeof value> (value); //not correct
to get all the Type information about value, but I just don't figure out how to get the generic <T> from value to pass it in the VResult<T> constructor;
You can create the generic instance like this:
object value = 1; //I don't know the runtime type of this
var genericType = typeof(VResult<>).MakeGenericType(value.GetType());
var genericInstance = Activator.CreateInstance(genericType,
new object[] { value });
And now you have a instance of VResult<int> with a value of 1. Is this what you were looking for?
I want to check if the method for certain parameters is implemented. In this scenario, I have for example these method overloads:
public class Transformations
{
public string TransformFrom(string s) { return s;}
public string TransformFrom(int i) { return "00" + i.ToString();}
public string TransformFrom(DateTime dt) { return
DateTime.ToString("MM/dd/yyyy HH:mm:ss.fff");}
}
Suppose I have decimal like:
object obj = 1M;
If I now call TransformFrom(obj), I get an exception.
Other part of my program returns unfortunately only objects, which really are concrete types like int or datetime. And I want to transform some of these objects to string so that those can be written to the log. So this is a runtime problem. Also I want that my Transformations-class is general enough to be used in other programs too, so there can be objects of any type.
Is there fast way to find out that this method overload does not exist?
Either way you are currently going to get a compile time error, even if there was an overload that accepted a decimal. You can approach this one of 2 ways depending on your needs:
To resolve this at compile time you have to cast to the correct type.
object obj = 1;
var objAsInt = (int) obj;
var result = transformationInstance.TransformFrom(objAsInt);
If there is no proper overload you will get a compile time error and you can resolve this at design time.
To resolve this at runtime use reflection to figure out if there is an overload of the type and if there is pass the instance.
object obj = 1;
var underlyingType = obj.GetType();
var method = typeof(Transformations).GetMethod("TransformFrom", new Type[] { underlyingType });
if(method != null)
{
var result = method.Invoke(transformationInstance, new []{obj});
}
It is possible to find out whether a given overload exists using reflection:
public static bool HasOverloadForArgument(Type targetType, string methodName, object arg)
{
var methodInfo = targetType.GetMethod(name: methodName, types: new[] { arg.GetType() });
return methodInfo != null;
}
Live sample
I'm not sure what is the whole idea here as there won't be much you can do when the transformation is not available during runtime.
Maybe, you'd just be best off using dynamic to avoid all the reflection stuff and caching required otherwise, e.g.
var boxedInt = (object)1;
var boxedFloat = (object)1f;
dynamic dynamicInt = boxedInt;
dynamic dynamicFloat = boxedFloat;
var intResult = new Transformations().TransformFrom(dynamicInt); // works
var floatResult = new Transformations().TransformFrom(dynamicFloat); // throws binder exception
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.
I have a function that returns this object:
var result = AjaxUserToPlacePaging();
//this is the object
object[] objcs = new object[1];
objcs[0] = new
{
countHereNow = countHereNow.ToString(),
countWillBeHere = countWillBeHere.ToString(),
countWasHere = countWasHere.ToString()
};
How can I extract the information from the object?
for example
int count = result[0].countHereNow;
the resun i nned the function to be object is because
i using jquery
and with the jquery it takes the object and converting it into json
You will need to use Reflection:
string countHereNow = string.Empty;
Type objType = result[0].GetType();
PropertyInfo prop = objType.GetPropertyInfo("countHereNow");
countHereNow = prop.GetValue(result[0], null) as string ?? string.Empty;
Typically I think returning an anonymous type is a bad idea, but maybe you have a reason for it. Otherwise, I would create a custom class and just return an array of that class type.
I recommend making a custom class, and storing that, instead of just storing an anonymous type into an "object" directly.
objcs[0] = new MyClass
{
countHereNow = countHereNow.ToString(),
countWillBeHere = countWillBeHere.ToString(),
countWasHere = countWasHere.ToString()
};
That will allow you to cast it back, when you retrieve:
MyClass myClass = result[0] as MyClass;
if (myClass != null)
{
int count = myClass.countHereNow;
}
There are tricks you can do to work with anonymous types, but in most cases, they just make the code less maintainable.
You need to use reflection (or something that uses reflection) to get the contents of your anonymous object outside the function where you create it. Maybe you should create a class and return instances of that instead?
You're currently declaring the array as an object array
object[] objcs = new object[1];
Declare it as a implicitly typed (var) array
var objcs = new [];
That way the objects you actually adding to the array won't be of SystemObject type but will be implicitly typed