3

我有以下方法可用于将对象转换为给定类型:

public static TTarget Convert<TTarget>(object source) where TTarget : new()
{
    var target = new TTarget();

    Type targetType = typeof (TTarget);
    foreach (PropertyInfo sourceProperty in source.GetType().GetProperties())
    {
        if (!sourceProperty.CanRead || (sourceProperty.GetIndexParameters().Length > 0))
            continue;

        PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);

        if ((targetProperty != null) && (targetProperty.CanWrite))
            targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
    }
    return target;
}

它适用于属性为值类型等的简单类,但复杂的属性需要映射到另一个类,目前还不太清楚如何去做。如果我将映射存储到静态属性中:

private static Dictionary<Type, Type> Mappings;

static TypeConverter()
{
    Mappings = new Dictionary<Type, Type>
        {
            {typeof (DbSpace), typeof (DmsSpace)},
            {typeof (DbDirectory), typeof (DmsDirectory)},
            {typeof (DbFile), typeof (DmsFile)}
        };
}

我似乎没有找到一种方法来利用这些信息来转换复杂的属性。如何使用上述映射来转换复杂的属性?

问题的症结在于:new我只有一个Type对象怎么调用?

4

4 回答 4

5

Activator.CreateInstance(type),对于那些认为我的回答不够“详尽”的人来说,这里有一个指向msdn的链接(获得 3 次反对票,以作为必要的简短回答)...

你也看过AutoMapper吗?

于 2013-05-26T21:40:16.720 回答
2

只要属性名称匹配,您就可以使用许多序列化程序(JavaScriptSerializer、XmlSerializer、Json.Net 等)对您的对象进行“深度转换”。

我将举一个使用JavaScriptSerializer的例子

var class1 = new Class1() { Property = "a", SubProperty = new SubClass1() { SubProperty = "b" } };
var class2 = Convert<Class2>(class1);


public static TTarget Convert<TTarget>(object source) where TTarget : new()
{
    var ser = new JavaScriptSerializer();
    var json = ser.Serialize(source);
    return ser.Deserialize<TTarget>(json);
}

.

public class Class1
{
    public string Property { get; set; }
    public SubClass1 SubProperty { get; set; }
}

public class SubClass1
{
    public string SubProperty { get; set; }
}


public class Class2
{
    public string Property { get; set; }
    public SubClass2 SubProperty { get; set; }
}

public class SubClass2
{
    public string SubProperty { get; set; }
}
于 2013-05-26T22:24:27.170 回答
1

使用AutoMapper而不是手动进行。

于 2013-05-26T21:51:00.090 回答
0

解决方案使用Activator.CreateInstance

public static class TypeConverter
{
    private static Dictionary<Type, Type> Mappings;

    static TypeConverter()
    {
        Mappings = new Dictionary<Type, Type>
            {
                {typeof (DbSpace), typeof (DmsSpace)},
                {typeof (DbDirectory), typeof (DmsDirectory)},
                {typeof (DbFile), typeof (DmsFile)}
            };
    }

    public static object Convert(object source, Type targetType)
    {
        var target = Activator.CreateInstance(targetType);

        foreach (PropertyInfo sourceProperty in source.GetType().GetProperties())
        {
            if (!sourceProperty.CanRead || (sourceProperty.GetIndexParameters().Length > 0))
                continue;

            PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);

            object value = sourceProperty.GetValue(source, null);

            if ((targetProperty != null) && (targetProperty.CanWrite))
            {
                if (value != null)
                {
                    Type valueType = value.GetType();
                    Type mappedTypeKey = Mappings.Keys.FirstOrDefault(valueType.IsAssignableFrom);
                    if (mappedTypeKey != null)
                    {
                        targetProperty.SetValue(target, Convert(value, Mappings[mappedTypeKey]), null);
                    }
                    else
                    {
                        targetProperty.SetValue(target, value, null);
                    }
                }
                else
                {
                    targetProperty.SetValue(target, null, null);
                }
            }

        }
        return target;
    }

    public static TTarget Convert<TTarget>(object source) where TTarget : class, new()
    {
        return Convert(source, typeof (TTarget)) as TTarget;
    }
}

使用我的 TypeConverter 类的示例代码:

spaces = ctx.DbSpaces.Include("Root").ToList().Select(TypeConverter.Convert<DmsSpace>).ToList();

使用 AutoMapper 的解决方案:

Mapper.CreateMap<DbSpace, DmsSpace>();
Mapper.CreateMap<DbSpace, IDmsSpace>();
Mapper.CreateMap<DbDirectory, DmsDirectory>();
Mapper.CreateMap<DbDirectory, IDmsDirectory>();

使用 AutoMapper 的示例代码:

spaces = ctx.DbSpaces.Include("Root").ToList().Select(Mapper.Map<DmsSpace>).ToList();
于 2013-05-27T08:10:54.417 回答