Set property Nullable<> by reflection - c#

I try to set a Nullable<> property dynamicly.
I Get my property ex :
PropertyInfo property = class.GetProperty("PropertyName"); // My property is Nullable<> at this time So the type could be a string or int
I want to set my property by reflection like
property.SetValue(class,"1256",null);
It's not working when my property is a Nullable<> Generic. So i try to find a way to set my property.
To know the type of my nullable<> property i execute
Nullable.GetUnderlyingType(property.PropertyType)
Any idea ?
I Try to create an instance of my Nullable<> property with
var nullVar = Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(new Type[] { Nullable.GetUnderlyingType(property.PropertyType) }));
But nullVar is always Null

If you want to convert an arbitrary string to the underlying type of the Nullable, you can use the Convert class:
var propertyInfo = typeof(Foo).GetProperty("Bar");
object convertedValue = null;
try
{
convertedValue = System.Convert.ChangeType("1256",
Nullable.GetUnderlyingType(propertyInfo.PropertyType));
}
catch (InvalidCastException)
{
// the input string could not be converted to the target type - abort
return;
}
propertyInfo.SetValue(fooInstance, convertedValue, null);
This example will work if the target type is int, short, long (or unsigned variants, since the input string represents a non-negative number), double, float, or decimal. Caveat: this is not fast code.

If it's a nullable int, you'll need to use an int parameter, not a string.
property.SetValue(klass,1256,null);
Note the change to klass, instead of class, as class is a reserved keyword. You could also use #class if absolutely necessary (quoting it).
If your property is a generic, then I think you'll probably need to use Convert to convert whatever you have to whatever you need.
var nullType = Nullable.GetUnderlyingType(property.PropertyType)
var value = Convert.ChangeType("1256", nullType );
property.SetValue(klass, value, null );

Here is a complete example showing how to do it:
using System;
using System.Reflection;
class Test
{
static void Main()
{
Foo foo = new Foo();
typeof(Foo).GetProperty("Bar")
.SetValue(foo, 1234, null);
}
}
class Foo
{
public Nullable<Int32> Bar { get; set; }
}
As others have mentioned you need to pass the right type to the SetValue function but your other reflection code is not quite right either. You need to get the type of the class in question before you can query for its members.
Edit: If I understand correctly you are trying to set a string value to any property via reflection. In order to do this you will need to do some type inspection and type conversion.
Here is an example of what I mean:
using System;
using System.Reflection;
class Test
{
static void Main()
{
Foo foo = new Foo();
PropertyInfo property = typeof(Foo).GetProperty("Bar");
Object value =
Convert.ChangeType("1234",
Nullable.GetUnderlyingType(property.PropertyType)
?? property.PropertyType);
property.SetValue(foo, value, null);
}
}
class Foo
{
public Nullable<Int32> Bar { get; set; }
}
This approach can be safely used regardless of whether or not the property is Nullable<>.

I hit this same problem as well as an issue with Convert.ChangeType not handling DateTimes on Nullables so I combined a couple of stackoverflow solutions with some .NET 4 dynamic magic to get something I think is kind of sweet. If you look at the code, we use dynamic to type the object to Nullable at run time, then the run time treats it differently and allows assignments of the base type to the nullable object.
public void GenericMapField(object targetObj, string fieldName, object fieldValue)
{
PropertyInfo prop = targetObj.GetType().GetProperty(fieldName);
if (prop != null)
{
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
dynamic objValue = System.Activator.CreateInstance(prop.PropertyType);
objValue = fieldValue;
prop.SetValue(targetObj, (object)objValue, null);
}
else
{
prop.SetValue(targetObj, fieldValue, null);
}
}
}

"1256" is a string, not an int.

public static void SetValue(object target, string propertyName, object value)
{
if (target == null)
return;
PropertyInfo propertyInfo = target.GetType().GetProperty(propertyName);
object convertedValue = value;
if (value != null && value.GetType() != propertyInfo.PropertyType)
{
Type propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
convertedValue = Convert.ChangeType(value, propertyType);
}
propertyInfo.SetValue(target, convertedValue, null);
}

Related

Dynamically set INT value to Nullable enum property without explicit type cast

I have a method that populates a DataTable to simple DTO object. To simplify I'll use this example:
public enum Gender : int
{
Male = 1,
Female = 2
}
public class Person
{
//...
public Gender? MyGender { get; set; }
}
static void Main(string[] args)
{
int intValue = 2; // value from DB
var o = new Person();
var prop = o.GetType().GetProperty("MyGender");
prop.SetValue(o, intValue , null); // <- Exception
}
The above throws:
Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[Test.Program+Gender]'.
If I declare MyGender as Gender (not Nullable) everything works fine.
It also works if I use an explicit Cast prop.SetValue(o, (Gender)intValue, null);
BUT, I don't want to (and can't) use the explicit cast: (Gender)intValue because I have no knowledge of the underlying "hard" type when I create the DTO object .
I was hoping for something like (which dose not compile):
var propType = prop.PropertyType;
prop.SetValue(o, (propType)intValue, null);
I also tried:
public static dynamic Cast(dynamic obj, Type castTo)
{
return Convert.ChangeType(obj, castTo);
}
var propType = prop.PropertyType;
prop.SetValue(o, Cast(intValue, propType), null);
Which throws:
Invalid cast from 'System.Int32' to
'System.Nullable`1[[Test.Program+Gender...]
I am at dead end. what are my options?
.NET Framework 4.6.2
This is the best I can come up with. There's an explicit check to see whether the property being assigned to is nullable, but I don't think you can avoid that.
public static void Main(string[] args)
{
int intValue = 2; // value from DB
var o = new Person();
var prop = o.GetType().GetProperty("MyGender");
// Check whether the property is a nullable. If it is, get the type of underling enum
// Otherwise, get the type of the enum directly from the property
var enumType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
// Convert the int to the enum type
var convertedValue = Enum.ToObject(enumType, intValue);
prop.SetValue(o, convertedValue , null);
}
Of course, bad things will happen if the property being assigned isn't an enum. var convertedValue = enumType.IsEnum ? Enum.ToObject(enumType, intValue); : intValue; would avoid that, if you needed it.
A "creative" option to consider is:
var o = new Person();
o.MyGender = 0;
o.MyGender += intValue;
This looks odd, but it does work since the constant 0 has a built-in implicit cast to enum (which other numbers do not).
So, you set it to 0, and then increment it to the actual number you are interested in. A key benefit here is you don't take the performance hit (and / or lack of type safety) of using reflection. You may want to add a comment to the code as to why you are doing it as well. ;)

I need to get a value of specific object's property, but don't know the type of the object

I have got an c# object and I don't know the type of this object. (i.e. object o)
What I know is that this object has a member called 'ID' of type int.
I wanted to get the value of this property but I am not good enough with reflection...
I can get a type and members of this object:
Type type = obj.GetType();
System.Reflection.MemberInfo[] member = type.GetMember("ID");
...but don't know what to do next :-)
Thanks for help in advance
Mariusz
Is this a public property? Is so then the easiest route is to use dynamic
int value = ((dynamic)obj).ID;
You can use:
Type type = obj.GetType();
PropertyInfo property = type.GetProperty("ID");
int id = (int) property.GetValue(obj, null);
Use PropertyInfo because you know it's a property, which makes things easier
Call GetValue to get the value, passing in obj as the target of the property and null for indexer arguments (as it's a property, not an index)
Cast the result to int as you already know it's going to be an int
Jared's suggestion of using dynamic is good too, if you're using C# 4 and .NET 4, although to avoid all the brackets I'd probably write it as:
dynamic d = obj;
int id = d.ID;
(unless you needed it in a single expression for some reason).
Can you use C# 4 ? In that case, you can use dynamic:
dynamic dyn = obj;
int id = dyn.ID;
public class TestClass
{
public TestClass()
{
// defaults
this.IdField = 1;
this.IdProperty = 2;
}
public int IdField;
public int IdProperty { get; set; }
}
// here is an object obj and you don't know which its underlying type
object obj = new TestClass();
var idProperty = obj.GetType().GetProperty("IdProperty");
if (idProperty != null)
{
// retrieve it and then parse to int using int.TryParse()
var intValue = idProperty.GetValue(obj, null);
}
var idField = obj.GetType().GetField("IdField");
if (idField != null)
{
// retrieve it and then parse to int using int.TryParse()
var intValue = idField.GetValue(obj);
}

How to get the default value for a ValueType Type with reflection

If I have a generic type parameter that is a value type and I want to know if a value is equal to the default I test it like this:
static bool IsDefault<T>(T value){
where T: struct
return value.Equals(default(T));
}
If I don't have a generic type parameter, then it seems like I would have to use reflection. If the method has to work for all value types, then Is there a better way to perform this test than what I am doing here? :
static bool IsDefault(object value){
if(!(value is ValueType)){
throw new ArgumentException("Precondition failed: Must be a ValueType", "value");
}
var #default = Activator.CreateInstance(value.GetType());
return value.Equals(#default);
}
On a side note, Is there anything I am not considering here with respect to evaluating Nullable structs?
I have found the following extension methods useful and will work for all types:
public static object GetDefault(this Type t)
{
return t.IsValueType ? Activator.CreateInstance(t) : null;
}
public static T GetDefault<T>()
{
var t = typeof(T);
return (T) GetDefault(t);
}
public static bool IsDefault<T>(T other)
{
T defaultValue = GetDefault<T>();
if (other == null) return defaultValue == null;
return other.Equals(defaultValue);
}
Old question but the accepted answer doesn't work for me so I submit this (probably can be made better):
public static object GetDefault(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var valueProperty = type.GetProperty("Value");
type = valueProperty.PropertyType;
}
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
With the following results:
typeof(int).GetDefault(); // returns 0
typeof(int?).GetDefault(); // returns 0
typeof(DateTime).GetDefault(); // returns 01/01/0001 00:00:00
typeof(DateTime?).GetDefault(); // returns 01/01/0001 00:00:00
typeof(string).GetDefault(); // returns null
typeof(Exception).GetDefault(); // returns null
I would require ValueType as the parameter to simplify:
static bool IsDefault(ValueType value){
var #default = Activator.CreateInstance(value.GetType());
return value.Equals(#default);
}
On a side note, Is there anything I am not considering here with
respect to evaluating Nullable structs?
Yes, you are missing something. By taking an object as the parameter in you are requiring calling code to box Nullable<T> types (which converts them to null or to their T Value). So if you pass a nullable, your is/throw will throw because null will never be a value type.
Edit: As #cdhowie said, you'll need to check for null. This will work for Nullable types as well.

'casting' with reflection

Consider the following sample code:
class SampleClass
{
public long SomeProperty { get; set; }
}
public void SetValue(SampleClass instance, decimal value)
{
// value is of type decimal, but is in reality a natural number => cast
instance.SomeProperty = (long)value;
}
Now I need to do something similar through reflection:
void SetValue(PropertyInfo info, object instance, object value)
{
// throws System.ArgumentException: Decimal can not be converted to Int64
info.SetValue(instance, value)
}
Note that I cannot assume that the PropertyInfo always represents a long, neither that value is always a decimal. However, I know that value can be casted to the correct type for that property.
How can I convert the 'value' parameter to the type represented by PropertyInfo instance through reflection ?
void SetValue(PropertyInfo info, object instance, object value)
{
info.SetValue(instance, Convert.ChangeType(value, info.PropertyType));
}
Thomas answer only works for types that implement IConvertible interface:
For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method. The method requires that conversion of value to conversionType be supported.
This code compile a linq expression that does the unboxing (if needed) and the conversion:
public static object Cast(this Type Type, object data)
{
var DataParam = Expression.Parameter(typeof(object), "data");
var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type));
var Run = Expression.Lambda(Body, DataParam).Compile();
var ret = Run.DynamicInvoke(data);
return ret;
}
The resulting lambda expression equals to (TOut)(TIn)Data where TIn is the type of the original data and TOut is the given type
The answer by Thomas is right, but I thought I would add my finding that Convert.ChangeType does not handle conversion to nullable types. To handle nullable types, I used the following code:
void SetValue(PropertyInfo info, object instance, object value)
{
var targetType = info.PropertyType.IsNullableType()
? Nullable.GetUnderlyingType(info.PropertyType)
: info.PropertyType;
var convertedValue = Convert.ChangeType(value, targetType);
info.SetValue(instance, convertedValue, null);
}
This code makes use of the following extension method:
public static class TypeExtensions
{
public static bool IsNullableType(this Type type)
{
return type.IsGenericType
&& type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
}
Contributing to jeroenh's answer, I would add that Convert.ChangeType crashes with a null value, so the line for getting the converted value should be:
var convertedValue = value == null ? null : Convert.ChangeType(value, targetType);
When the Type is a Nullable Guid then none of the above proposed solutions work.
Invalid cast from 'System.DBNull' to 'System.Guid' exception is thrown at Convert.ChangeType
To fix that change to:
var convertedValue = value == System.DBNull.Value ? null : Convert.ChangeType(value, targetType);
This is a very old question but I thought I'd chime in for ASP.NET Core Googlers.
In ASP.NET Core, .IsNullableType() is protected (amongst other changes) so the code is a tad different. Here's #jeroenh's answer modified to work in ASP.NET Core:
void SetValue(PropertyInfo info, object instance, object value)
{
Type proptype = info.PropertyType;
if (proptype.IsGenericType && proptype.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
proptype = new NullableConverter(info.PropertyType).UnderlyingType;
}
var convertedValue = Convert.ChangeType(value, proptype);
info.SetValue(instance, convertedValue);
}

Cast a property to its actual type dynamically using reflection

I need to cast a property to its actual type dynamically. How do I/Can I do this using reflection?
To explain the real scenario that I am working on a bit. I am trying to call the "First" extension method on an Entity Framework property. The specific property to be called on the Framework context object is passed as a string to the method (as well as the id of the record to be retrieved). So I need the actual type of the object in order to call the First method.
I can't use the "Where" method on the object as the lambda or delegate method still needs the actual type of the object in order to access the properties.
Also as the object is generated by the Entity Framework I can't cast the type to an interface and operate on that.
This is scenario code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
namespace NmSpc
{
public class ClassA
{
public int IntProperty { get; set; }
}
public class ClassB
{
public ClassA MyProperty { get; set; }
}
public class ClassC
{
static void Main(string[] args)
{
ClassB tester = new ClassB();
PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
//get a type unsafe reference to ClassB`s property
Object property = propInfo.GetValue(tester, null);
//get the type safe reference to the property
ClassA typeSafeProperty = property as ClassA;
//I need to cast the property to its actual type dynamically. How do I/Can I do this using reflection?
//I will not know that "property" is of ClassA apart from at runtime
}
}
}
public object CastPropertyValue(PropertyInfo property, string value) {
if (property == null || String.IsNullOrEmpty(value))
return null;
if (property.PropertyType.IsEnum)
{
Type enumType = property.PropertyType;
if (Enum.IsDefined(enumType, value))
return Enum.Parse(enumType, value);
}
if (property.PropertyType == typeof(bool))
return value == "1" || value == "true" || value == "on" || value == "checked";
else if (property.PropertyType == typeof(Uri))
return new Uri(Convert.ToString(value));
else
return Convert.ChangeType(value, property.PropertyType); }
I had some time so I tried to solve my problem using VS2010 and I think I was right previously when I though that the dynamic keywork would 'solve' my question. See the code below.
using System.Reflection;
namespace TempTest
{
public class ClassA
{
public int IntProperty { get; set; }
}
public class ClassB
{
public ClassB()
{
MyProperty = new ClassA { IntProperty = 4 };
}
public ClassA MyProperty { get; set; }
}
public class Program
{
static void Main(string[] args)
{
ClassB tester = new ClassB();
PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
//get a type unsafe reference to ClassB`s property
dynamic property = propInfo.GetValue(tester, null);
//casted the property to its actual type dynamically
int result = property.IntProperty;
}
}
}
Once you get the reflected type, you can use Convert.ChangeType().
Having a variable of a specific type is really only useful at compile time, and will not help you at runtime in using it in this way. Try to write the code where you would utilize this... you'll find that it keeps pushing the requirement to know the type to compile time at some level (maybe further up the call chain, but you'll still eventually need to type the concrete type for this to be useful).
One thing to keep in mind, though - if your type is a reference type, the object is still truly the type you've created. It's not like there is a benefit to having the object saved as your type vs. object. This is the beauty of reflection (as well as part of why it works). There really is no reason to try to "change" it's type at runtime in a cast, since it's still going to be an object.
How about setting the root value as a string and then carry it around as a string until you need to convert it to the target type?
Though I should post the solution to the real world problem.
string objectType = "MyProperty";
using (MyEntitiesContext entitiesContext = new MyEntitiesContext())
{
try
{
string queryString = #"SELECT VALUE " + objectType+ " FROM MyEntitiesContext." + objectType + " AS " + objectType + " WHERE " + objectType + ".id = #id";
IQueryable<Object> query = entitiesContext.CreateQuery<Object>(queryString, new ObjectParameter("id", objectId));
foreach (Object result in query)
{
return result;
}
}
catch (EntitySqlException ex)
{
Console.WriteLine(ex.ToString());
}
}
return null;
I think the new CLR4 dynamic keywork might be the "nice" solution.
Thanks for all the responces.
Type resultType = typeof(T);
IEnumerable<PropertyDescriptor> properties = TypeDescriptor.GetProperties(resultType).Cast<PropertyDescriptor>();
object instance = Activator.CreateInstance(resultType);
var objValue = "VALUE FOR HEADER";
var resultHeader = "HeaderName";
var prop = properties.Single(p => string.Equals(p.Name, resultHeader, StringComparison.InvariantCultureIgnoreCase));
var targetType = Nullable.GetUnderlyingType(prop.PropertyType) !=null Nullable.GetUnderlyingType(prop.PropertyType):prop.PropertyType;
objValue = Convert.ChangeType(objValue , targetType);
prop.SetValue(instance, objValue );
//return instance;
You want to access a property of another property of an object. All you really need is one method that repeats itself, i.e. the overload principle. I tried that and it worked.
public static object PropValue(object src, string firstPropName, string secoundPropName,string threedPropName)
{ // This will lead to Property of Property of the given InstanceProperty
var secoundProperty = PropValue(src, firstPropName, secoundPropName);
return PropValue(secoundProperty, threedPropName);
}
public static object PropValue(object src,string firstPropName, string secondPropName)
{ // This will lead to Property of an given InstanceProperty
var FirstProperty = PropValue(src, firstPropName);
return PropValue(FirstProperty, secondPropName);
}
public static object PropValue(object src, string propName)
{
// This will lead to the given InstanceProperty
return src.GetType().GetProperty(propName).GetValue(src, null);
}

Categories