【问题标题】:dynamic type casting in custom ValueInjecter injection自定义 ValueInjecter 注入中的动态类型转换
【发布时间】:2011-08-17 03:39:36
【问题描述】:

我为ValueInjecter 创建了一个自定义注入类,它为通用子集合进行递归注入,但它适用于现有目标对象,而不是像 VI 站点上的“CloneInjection”示例那样进行克隆。但是,目前我正在转换为已知类型 (ICollection),因此注入类仅适用于一种硬编码类型。我似乎无法找到一种动态投射泛型的方法,有什么建议吗?这是我的“RecursiveInjection”类的 SetValue 代码。

//for value types and string just return the value as is
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string))
  return c.SourceProp.Value;

if (c.SourceProp.Type.IsGenericType)
  {
  //handle IEnumerable<> also ICollection<> IList<> List<>
  if (c.SourceProp.Type.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
    {
      var t = c.TargetProp.Type.GetGenericArguments()[0];
      if (t.IsValueType || t == typeof(string)) return c.SourceProp.Value;

      //get enumerable object in target
     var targetCollection = c.TargetProp.Value as ICollection<MyTargetType>;
     //possible to cast dynamically?

     foreach (var o in c.SourceProp.Value as IEnumerable)
     {
       //get ID of source object
       var sourceID = (int)o.GetProps().GetByName("ID").GetValue(o);
       //find matching target object if there is one
       var target = targetCollection.SingleOrDefault(x => x.ID == sourceID);
       if (target != null)
       {
         target.InjectFrom<RecursiveInjection>(o);
       }
     }
    return targetCollection;
  }
}

谢谢,丹奥

【问题讨论】:

  • 你能告诉我你想达到什么目标吗?
  • @Omu - 看看我在 VI “深度克隆”页面上的帖子 - valueinjecter.codeplex.com/… - 我正在更新 EF POCO 实体,因此必须直接更新目标对象属性而不是创建克隆
  • 我了解到您正在尝试执行类似克隆注入但没有克隆的操作,并且您成功使用 但您需要它更加动态(也许您也可以尝试制作一个通用的注入),我想知道的是为什么/正在尝试做什么,您的初始源和目标对象是什么以及您想从一​​个注入到另一个
  • @Omu - 我正在尝试创建一个可重用的注入,它将注入从 EF 上下文加载的 POCO 实体,其值来自通过 MVC 表单发布的类似视图模型对象,我希望注入递归处理所有子集合及其属性(例如,具有 Orders 子集合的 Customer 实体)。 Customer.Orders = CustomerViewModel.Orders 不适用于 EF,这就是克隆注入不起作用的原因。有意义吗?
  • 这是可行的,但是集合存在问题,例如,如果在源端删除了集合中间的项目,您如何知道源集合中的哪个对象要注入目标集合的哪个对象,不能一一拿来认为它们的顺序相同,因为它们可能不是

标签: c# .net dynamic casting valueinjecter


【解决方案1】:

我只会使用 ICollection 并覆盖 Equals( object ) 进行比较。

public class MyTargetType
{
    public override bool Equals( object obj )
    {
        return ( obj is MyTargetType )
                    ? this.ID == ( ( MyTargetType ) obj ).ID
                    : false;
    }
}

然后在您的循环中,您将直接匹配对象而不是使用反射。

var target = targetCollection.SingleOrDefault( x => x.Equals( o ) );

【讨论】:

  • 感谢您的建议 - 我认为这只会解决部分问题。如果我只是将 targetCollection 转换为 ICollection,则 SingleOrDefault 不是对象上的有效方法
【解决方案2】:

虽然我无法找到动态转换泛型集合的方法,但我确实找到了解决我试图解决的潜在问题的方法,即注入包含子集合的 EF POCO 对象(一个-对许多“导航属性”)。

我刚刚从 EF 4.0 升级到 EF 4.1,哈利路亚! EF 4.1 现在实际上管理子集合上的对象合并。升级后,我可以照原样使用 CloneInjection。

【讨论】:

  • 所以你不再需要这个了:) ?
  • @Omu - 看起来这是一个我不再需要解决的问题,尽管它仍然是一个有趣的练习。你是对的,我发布的代码只处理一对一的更新。最终,我希望能找出处理添加和删除项目的逻辑。
  • 嗯,你可以,但你不能为任何对象,而是为具有 Id 属性的 IEntity 这样做,这样你就可以按 Id 比较对象
【解决方案3】:

我想这就是你要找的东西:

    public class M1
    {
        public string Name { get; set; }
    }

    public class M2
    {
        public string Name { get; set; }
    }

    [Test]
    public void Cast()
    {
        object source = new List<M1> {new M1 {Name = "o"}};
        object target = new List<M2>();


        var targetArgumentType = target.GetType().GetGenericArguments()[0];

        var list = Activator.CreateInstance(typeof(List<>).MakeGenericType(targetArgumentType));
        var add = list.GetType().GetMethod("Add");

        foreach (var o in source as IEnumerable)
        {
            var t = Activator.CreateInstance(targetArgumentType);
            add.Invoke(list, new[] { t.InjectFrom(o) });
        }

        target = list;

        Assert.AreEqual("o", (target as List<M2>).First().Name);
    }

在 .NET 4 中,您可以使用动态来缩短这段时间

【讨论】:

    猜你喜欢
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2012-06-23
    • 2010-09-09
    • 1970-01-01
    • 2020-08-10
    相关资源
    最近更新 更多