C # как определить универсальный тип динамически - PullRequest
0 голосов
/ 05 января 2019

У меня есть метод, в котором мне нравится выполнять несколько разных приведений, используя механизм отражения.

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

У меня есть словарь, и я хочу преобразовать его в пользовательский класс, каждый ключ из словаря является свойством, а каждое значение словаря является значением этого свойства. Проблема возникает в двух случаях, когда оба, тип свойства класса и тип значения словаря являются примитивами, но имеют различный тип (например, свойство имеет тип int, но значение словаря является длинным), вторая проблема возникает, когда значением свойства является другой пользовательский класс и в в этом случае значением словаря всегда является другой словарь

Как я могу динамически определить необходимые приведения / приведения?

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Лучшим подходом к решению этой проблемы является применение принципа дяди Боба S.O.L.I.D, который является принципом Открытого закрытия. Вот классический пример этого принципа

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;
    }
} 

таким образом, вам не нужно создавать если еще дерево, но с реализацией абстрактного класса вы должны реализовывать метод Area каждый раз, когда вы используете его с любым вашим классом. Надеюсь, что служат цели

0 голосов
/ 05 января 2019

Начните с поиска, совместимы ли типы с

if (t.IsAssignableFrom(t2))

В противном случае конвертировать с

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

Это должно обрабатывать много случаев.

Поскольку вы должны вызывать метод рекурсивно с типом, известным только во время выполнения, лучше иметь не универсальную перегруженную версию GetObject. Оригинальный метод вызывает только неуниверсальный

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

Обратите внимание, что параметры универсального типа всегда разрешаются во время компиляции. Поскольку вы должны разрешать тип динамически во время выполнения, они являются скорее помехой. Вы можете создать общий вызов метода, используя отражение, но я не вижу в этом никакого преимущества. Это сложно и не безопасно типа. Безопасность типов может быть обеспечена только компилятором.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...