通过属性进行类转换

时间:2013-02-20 16:03:10

标签: c# wcf dynamic attributes type-conversion

代码

public class Test1
{
    [Conversion("UserId")]
    Public int id { get; set; }

    [Conversion("UserValue")]
    public int value { get; set; }

    [Conversion("UserInfo")]
    public List<Test2> info { get; set; }
}
public class User
{
    public int UserId { get; set; }
    public int UserValue { get; set; }      
    public List<UserInformation> UserInfo { get; set; }
}

public class Test2
{
    [Conversion("UserId")]
    public int id { get; set; }

    [Conversion("UserName")]
    public string name { get; set; }

    [Conversion("UserLocation")]
    public string location { get; set; }
}

public class UserInformation
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string UserLocation { get; set; }
}

public class ConversionAttribute    
{
    public string Name { get; set; }
    public ConversionAttribute(string name)
    {
        this.Name = name;
    }
}

public dynamic Convert(dynamic source, Type result)
{
    var p = Activator.CreateInstance(result);
    foreach (var item in source.GetType().GetProperties().Where(m => m.GetCustomAttributes(typeof(ConversionAttribute)).Count() > 0))
    {
        p.GetType().GetProperty(item.GetCustomAttributes(typeof(ConversionAttribute)).Cast<ConversionAttribute>().Name).Value = item.GetValue(source,null); // This should work for system types... but not for lists / custom models.          
    }       
}

public void DoShit()
{
    var t1 = new Test1 { id = 1, name = value = "Test", info = new Test2 { id = 1, name = "MyName", location = "UserLocation" } };
    var obj = Convert(t1, typeof(User));
}

场合

我的任务是将我们的数据库模型转换为我们的WCF模型。它们在几个方面有所不同,我在上面的示例代码中稍微展示了一些。

我已经设法使用Activator.CreateInstance(result)创建实例,我可以使用source.GetType().GetProperties()复制所有属性,但是当涉及到模型(自定义类)或者a时,我似乎遇到了问题列表。

问题

我不知道如何处理自定义类或列表(系统类型以及自定义类)。

在我的旧方法中,我使用了两种方法,一种用于正常转换,一种用于列表转换..但我的老板不批准它所以我想知道是否可以为每个方法使用一种方法使用而不检查类型是列表,自定义类还是系统类型

这必须是完全通用的并且使用属性的主要原因是因为我们计划在几个项目中使用此方法以及超过100个模型。

1 个答案:

答案 0 :(得分:0)

      Here is something that I tried. It works albeit it's a little slow on lager object graphs. One could use expression trees           which are harder to get but give a really impressive performance.



      'private static IEnumerable<Tuple<PropertyInfo, PropertyInfo>> MapProperties(Type source, Type target)
        {
            var targetProperies = target.GetProperties();

            foreach (var property in source.GetProperties())
            {
                var conversionAttribute =
                    property.GetCustomAttributes(typeof (ConvertAttribute), false).FirstOrDefault() as
                    ConvertAttribute;

                if (conversionAttribute == null)
                    throw new InvalidOperationException(
                        String.Format("Source property {0} doesn't have ConvertAttribute defined", property.Name));

                var targetProperty = targetProperies.FirstOrDefault(p => p.Name == conversionAttribute.Name);


                if (targetProperty == null)
                    throw new InvalidOperationException(String.Format(
                        "Target type doesn't have {0} public property", conversionAttribute.Name));

                yield return Tuple.Create(targetProperty, property);
            }
        }

        public static bool IsIList(Type type)
        {
            return type.GetInterface("System.Collections.Generic.IList`1") != null;
        }


        private static object Convert(object source, Type resaultType)
        {
            var resault = Activator.CreateInstance(resaultType);

            var sourceType = source.GetType();


            if (IsIList(resaultType) && IsIList(sourceType))
            {
                var sourceCollection = source as IList;

                var targetCollection = resault as IList;

                var argument = resaultType.GetGenericArguments()[0];

                if (argument.IsAssignableFrom(sourceType.GetGenericArguments()[0]))
                {
                    foreach (var item in sourceCollection)
                    {
                        targetCollection.Add(item);
                    }
                }
                else
                {
                    foreach (var item in sourceCollection)
                    {
                        targetCollection.Add(Convert(item, argument));
                    }
                }
            }
            else
            {
                foreach (var map in MapProperties(sourceType, resaultType))
                {
                    if (map.Item1.PropertyType.IsAssignableFrom(map.Item2.PropertyType))
                    {
                        map.Item1.SetValue(resault, map.Item2.GetValue(source, null), null);
                    }
                    else
                    {
                        map.Item1.SetValue(resault,
                                           Convert(map.Item2.GetValue(source, null), map.Item1.PropertyType), null);
                    }
                }
            }
            return resault;
        }'