复制具有不同名称空间的两个相同对象(递归反射)

本文关键字:反射 递归 两个 对象 空间 复制 | 更新日期: 2023-09-27 18:01:15

我在c#中使用多个工作区,这些工作区有一个特定的类,每个工作区的类总是相同的。我希望能够拥有这个类的副本,以便能够在不处理名称空间差异的情况下使用它。示例:

namespace1 {
    class class1{
        public class2;
    }
    class class2{
        public string;
    }
}
namespace2 {
    class class1{
        public class2;
    }
    class class2{
        public string;
    }
}

在我复制的类中,我有一个函数可以将所有数据复制到命名空间的一个类中。如果我只有c#标准类型,它就起作用了。我在处理class2对象(它也来自不同的命名空间(时就得到了exeption("对象与目标类型不匹配。"(

public Object toNamespaceClass(Object namespaceClass)
{
    try
    {
        Type fromType = this.GetType();
        Type toType = namespaceClass.GetType();
        PropertyInfo[] fromProps = fromType.GetProperties();
        PropertyInfo[] toProps = toType.GetProperties();
        for (int i = 0; i < fromProps.Length; i++)
        {
            PropertyInfo fromProp = fromProps[i];
            PropertyInfo toProp = toType.GetProperty(fromProp.Name);
            if (toProp != null)
            {
                toProp.SetValue(this, fromProp.GetValue(namespaceClass, null), null);
            }
        }
    }
    catch (Exception ex)
    {
    }
    return namespaceClass;
}

任何人都知道如何处理这种"递归反射"。

我希望一切都可以理解。

谢谢,再见!

编辑:我想我已经解决了(至少在我的脑海中(,我明天会在工作中尝试这个解决方案。如果一个属性不是标准类型,那么将我的函数从类中取出并递归使用它可能是解决方案。

复制具有不同名称空间的两个相同对象(递归反射)

BinaryFormatter在.Net 4.5中不起作用,因为它会记住实例是从什么类型的类创建的。但对于JSON格式,则不然。JSON序列化程序由Microsoft在DataContractJosnSerializer中实现。

这项工作:

    public static T2 DeepClone<T1, T2>(T1 obj)
    {
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T1));
        DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T2));
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, obj);
            ms.Position = 0;
            return (T2)deserializer.ReadObject(ms);
        }
    }

并使用如下:

   var b = DeepClone<A, B>(a);

我也遇到了类似的问题。我使用了类似的类,但仅在名称空间方面有所不同。作为一个快速的解决方案,我执行了以下步骤,它是有效的。

  1. 将源类序列化为XML
  2. 在SerializedXML中,将源命名空间替换为目标命名空间
  3. 使用目标类型取消序列化

我知道上面的方法会带来性能开销,但实现起来很快而且没有错误。

我解决了它,只是想让你知道我是如何做到的:这个解决方案非常完美,因为它只处理一维数组,而不是更多。

public static Object CopyObject(Object from , Object to)
{
    try
    {
        Type fromType = from.GetType();
        Type toType = to.GetType();
        PropertyInfo[] fromProps = fromType.GetProperties();
        PropertyInfo[] toProps = toType.GetProperties();
        for (int i = 0; i < fromProps.Length; i++)
        {
            PropertyInfo fromProp = fromProps[i];
            PropertyInfo toProp = toType.GetProperty(fromProp.Name);
            if (toProp != null)
            {
                if (toProp.PropertyType.Module.ScopeName != "CommonLanguageRuntimeLibrary")
                {
                    if (!toProp.PropertyType.IsArray)
                    {
                        ConstructorInfo ci = toProp.PropertyType.GetConstructor(new Type[0]);
                        if (ci != null)
                        {
                            toProp.SetValue(to, ci.Invoke(null), null);
                            toProp.SetValue(to, gestionRefelexion.CopyObject(fromProp.GetValue(from, null), toProp.GetValue(to, null)), null);
                        }
                    }
                    else
                    {
                        Type typeToArray = toProp.PropertyType.GetElementType();
                        Array fromArray = fromProp.GetValue(from, null) as Array;
                        toProp.SetValue(to, copyArray(fromArray, typeToArray), null);
                    }
                }
                else
                {
                    toProp.SetValue(to, fromProp.GetValue(from, null), null);
                }
            }
        }
    }
    catch (Exception ex)
    {
    }
    return to;
}
public static Array copyArray(Array from, Type toType)
{
    Array toArray =null;
    if (from != null)
    {
        toArray= Array.CreateInstance(toType, from.Length);
        for (int i = 0; i < from.Length; i++)
        {
            ConstructorInfo ci = toType.GetConstructor(new Type[0]);
            if (ci != null)
            {
                toArray.SetValue(ci.Invoke(null), i);
                toArray.SetValue(gestionRefelexion.CopyObject(from.GetValue(i), toArray.GetValue(i)), i);
            }
        }
    }
    return toArray;
}

希望这能帮助一些人。谢谢你帮助大家。干杯

public static T DeepClone<T>(T obj)
{
 using (var ms = new MemoryStream())
 {
   var formatter = new BinaryFormatter();
   formatter.Serialize(ms, obj);
   ms.Position = 0;
   return (T) formatter.Deserialize(ms);
 }
}

从这里

来自不同名称空间的两个相同或相似的对象?

你有这个:

namespace Cars
{
  public class car {
    public string Name;
    public void Start() { ... }
  }
} 

namespace Planes
{
  public class plane {
    public string Name;
public void Fly() { ... }
  }
} 

是时候应用一些类继承了:

namespace Vehicles
{
  public class vehicle
  {
    public string Name;
  } // class
} // namespace
using Vehicles;
namespace Cars
{
  public class car: vehicle
  {
    public string Name;
    public void Start() { ... }
  }  // class
} // namespace
using Vehicles;
namespace Planes
{
  public class plane: vehicle
  {
    public void Fly() { ... }
  }
} 

要复制,有一个复制方法或构造函数,但是,我更喜欢自定义方法:

namespace Vehicles
{
  public class vehicle {
    public string Name;
    public virtual CopyFrom (vehicle Source)
    {
      this.Name = Source.Name;
      // other fields
    }
  } // class
} // namespace 

干杯。

您要么需要将所有重复的类重构为一个共享类,要么实现所有不同类都实现的公共接口。如果您真的不能修改底层类型,请为每个实现公共接口的类型创建一个子类。

是的,你可以通过反思来做到。。。但你真的不应该这样做,因为你最终会得到脆弱、容易出错的代码。

使用协议缓冲区可以很好地解决这个问题,因为协议缓冲区不包含任何关于它们序列化的类型的元数据。具有相同字段的两个类&属性序列化为完全相同的位。

这里有一个小函数,它将从原始类型O更改为复制类型C

static public C DeepCopyChangingNamespace<O,C>(O original)
{
    using (MemoryStream ms = new MemoryStream())
    {
        Serializer.Serialize(ms, original);
        ms.Position = 0;
        C c = Serializer.Deserialize<C>(ms);
        return c;
    }
}

使用

namespace1.class1 orig = new namespace1.class1();
namespace2.class1 copy = 
    DeepCopyChangingNamespace<namespace1.class1, namespace2.class1>(orig);