【问题标题】:Class conversion via Attributes通过属性进行类转换
【发布时间】:2013-02-20 16:03:10
【问题描述】:

代码

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() 复制所有属性,但在涉及模型(自定义类)或列表时我似乎遇到了问题。

问题

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

在我的旧方法中,我使用了两种方法,一种用于普通转换,一种用于列表转换。但我的老板不同意,所以我想知道是否可以为每个人使用一种方法使用时不检查类型是列表、自定义类还是系统类型

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

【问题讨论】:

  • 有什么理由不能重新设计你的数据库,而不是使用像实体框架这样的 ORM 来重新导入你的模型类?
  • 我们的数据库是完全动态的,对于一个模型,一个字段可能意味着“名称”,但对于另一个模型,它可能意味着“描述”
  • 如果您不想单独处理每个案例,您可以通过自定义 DynamicObject 包装您的源类型,它将属性访问调用路由到您的源类型。
  • 那么你只是想从数据库表中生成 POCO 并且名称不同吗?如果是这样,T4 模板将是您的最佳选择。它可以为您的整个数据库生成 POCO。然后您可以使用自定义属性来映射您想要的不同名称。我会切换它,所以 WCF 合同名称是属性名称,数据库列名称是属性。

标签: c# wcf dynamic attributes type-conversion


【解决方案1】:
      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;
        }'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2019-03-28
    相关资源
    最近更新 更多