Сопоставление ExpandoObject в другой тип объекта


Я работаю на вспомогательный метод, который будет отображать свойства из ExpandoObject к эксплуатации объект, и было интересно, если код может быть очищен или сделано более эффективно. В настоящее время она имеет правильное поведение из простого теста.

public static class Mapper
{
    public static void Map<T>(ExpandoObject source, T destination)
    {
        IDictionary<string, object> dict = source;
        var type = destination.GetType();

        foreach (var prop in type.GetProperties())
        {
            var lower = prop.Name.ToLower();
            var key = dict.Keys.SingleOrDefault(k => k.ToLower() == lower);

            if (key != null)
            {
                prop.SetValue(destination, dict[key], null);
            }
        }
    }
}

Полный тест можно увидеть здесь. В настоящее время нет проверял тип. Это было бы добавить?



21018
10
задан 25 февраля 2011 в 11:02 Источник Поделиться
Комментарии
1 ответ

Я придумал несколько изменений, которые на самом деле должны его ускорить.

// By using a generic class we can take advantage
// of the fact that .NET will create a new generic type
// for each type T. This allows us to avoid creating
// a dictionary of Dictionary<string, PropertyInfo>
// for each type T. We also avoid the need for the
// lock statement with every call to Map.
public static class Mapper<T>
// We can only use reference types
where T : class
{
private static readonly Dictionary<string, PropertyInfo> _propertyMap;

static Mapper()
{
// At this point we can convert each
// property name to lower case so we avoid
// creating a new string more than once.
_propertyMap =
typeof(T)
.GetProperties()
.ToDictionary(
p => p.Name.ToLower(),
p => p
);
}

public static void Map(ExpandoObject source, T destination)
{
// Might as well take care of null references early.
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");

// By iterating the KeyValuePair<string, object> of
// source we can avoid manually searching the keys of
// source as we see in your original code.
foreach (var kv in source)
{
PropertyInfo p;
if (_propertyMap.TryGetValue(kv.Key.ToLower(), out p))
{
var propType = p.PropertyType;
if (kv.Value == null)
{
if (!propType.IsByRef && propType.Name != "Nullable`1")
{
// Throw if type is a value type
// but not Nullable<>
throw new ArgumentException("not nullable");
}
}
else if (kv.Value.GetType() != propType)
{
// You could make this a bit less strict
// but I don't recommend it.
throw new ArgumentException("type mismatch");
}
p.SetValue(destination, kv.Value, null);
}
}
}
}

8
ответ дан 26 февраля 2011 в 12:02 Источник Поделиться