roroinpho21
roroinpho21

Reputation: 742

C# how to detect generic type dynamically

I have a method in which I like to perform a few different casts using reflection mechanism.

private static T GetObject<T>(Dictionary<string, object> dict)
{
    Type type = typeof(T);
    var obj = Activator.CreateInstance(type);
    foreach (var kv in dict)
    {
        var p = type.GetProperty(kv.Key);
        Type t = p.PropertyType;
        Type t2 = kv.Value.GetType();
        if (t == t2)
        {
            p.SetValue(obj, kv.Value);
        }
        else if (!IsPrimitive(p.PropertyType)) 
        {
            p.SetValue(obj, GetObject<class of p>((Dictionary<string, object>) kv.Value)); //???
        }
        else
        {
            p.SetValue(obj, (primitive)(kv.Value)); //???                    
        }
    }
    return (T)obj;
}

EDITED

I have a dictionary and I want to convert it to a custom class, each key from dictionary is a property and each dictionary value is the value for that property. The problems appears in two cases, when both, the class property type and dictionary value type are primitives but they have different type (e.g. property is int but dictionary value is long), the second problem appears when property value is another custom class and in that case the dictionary value is always another dictionary

How can I detect dynamically the necessary cast/casts?

Upvotes: 2

Views: 200

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112762

Start by looking if the types are assignment compatible with

if (t.IsAssignableFrom(t2))

Otherwise convert with

object converted = Convert.ChangeType(kv.Value, t);

This should handle a lot of cases.

Since you must call the method recursively with a type only know at runtime, it is better to have a non-generic overloaded version of GetObject. The original method only calls the non-generic one

private static T GetObject<T>(Dictionary<string, object> dict)
    where T : class, new() // Suggested by Brett Caswell.
{
    return (T)GetObject(dict, typeof(T));
}

Note that generic type parameters are always resolved at compile-time. Since you must resolve the type dynamically at run-time, they are more of a hindrance here. You could construct a generic method call using reflection, but I don't see any advantage in doing so. It is complicated and not type safe. Type safety can only be enforced by the compiler.

private static object GetObject(Dictionary<string, object> dict, Type objectType)
{
    object obj = Activator.CreateInstance(objectType);
    foreach (var kv in dict) {
        PropertyInfo prop = objectType.GetProperty(kv.Key);
        Type propType = prop.PropertyType;
        object value = kv.Value;
        if (value == null) {
            if (propType.IsValueType) { // Get default value of type.
                value = Activator.CreateInstance(propType);
            }
        } else if (value is Dictionary<string, object> nestedDict) {
            value = GetObject(nestedDict, propType);
        } else if (!propType.IsAssignableFrom(value.GetType())) {
            value = Convert.ChangeType(value, propType);
        }
        prop.SetValue(obj, value);
    }
    return obj;
}

Upvotes: 2

Zain Ali
Zain Ali

Reputation: 65

Better approach of this problem is apply one of uncle Bob's S.O.L.I.D principle which is Open close principle. Here is the Classic Example of this principle

public abstract class Shape
{
        public abstract double Area();
 } 

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area()
    {
        return Width*Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area()
    {
        return Radius*Radius*Math.PI;
    }
} 

by this way you don't have to make if else tree but with implementing the abstract class you have to implement Area method every time you use it with any of your Class. Hope that serve the purpose

Upvotes: -1

Related Questions