Скопируйте два идентичных объекта с разными пространствами имен (рекурсивное отражение) - PullRequest
3 голосов
/ 06 июля 2011

Я работаю в c # с несколькими рабочими пространствами, которые имеют один определенный класс, который всегда одинаков в каждом рабочем пространстве. Я хотел бы иметь возможность иметь копию этого класса, чтобы иметь возможность работать с ним без учета различий в пространствах имен. пример:

namespace1 {
    class class1{
        public class2;
    }

    class class2{
        public string;
    }

}

namespace2 {
    class class1{
        public class2;
    }

    class class2{
        public string;
    }
}

В моем скопированном классе у меня есть функция для копирования всех данных в один из классов пространства имен. Это работает, если у меня есть только стандартные типы c #. Я получил исключение («Объект не соответствует типу цели.»), Как только я имею дело с объектом класса 2 (который также из разных пространств имен)

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;
}

Кто-нибудь имеет представление о том, как бороться с этим видом "рекурсивного отражения".

Я надеюсь, что все понятно.

Спасибо, пока!

Редактировать: Я думаю, что я получил решение (по крайней мере, на мой взгляд), я попробую решение обратно на работу завтра. Возможно, решение - убрать мою функцию из класса и использовать ее рекурсивно, если свойство не является стандартным типом.

Ответы [ 7 ]

6 голосов
/ 31 января 2014

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);
5 голосов
/ 10 ноября 2011

У меня была похожая проблема. Я должен использовать похожие классы, но разные только с точки зрения пространства имен. В качестве быстрого решения я выполнил следующие шаги, и это работает.

  1. Сериализация исходного класса в XML.
  2. В SerializedXML замените исходное пространство имен целевым.
  3. Десериализация с типом цели.

Я знаю, что вышеописанный способ приводит к снижению производительности, но он быстр в реализации и не содержит ошибок.

2 голосов
/ 07 июля 2011

Я решил, просто чтобы вы знали, как я это сделал: Это идеальное решение, потому что оно обрабатывает только один массив измерений, не более.

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;
}

Надеюсь, что это может помочь некоторым людям. Спасибо за помощь всем. Приветствия

0 голосов
/ 25 июля 2012

Эту проблему можно изящно решить, используя Буферы протокола , поскольку в буферах протокола нет метаданных о типе, который они сериализуют. Два класса с одинаковыми полями и свойствами сериализуются в точные одинаковые биты.

Вот небольшая функция, которая изменится с 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);
0 голосов
/ 08 июля 2011

Вам необходимо либо реорганизовать все ваши дублирующиеся классы в один общий класс, либо реализовать общий интерфейс, который реализуют все ваши различные классы.Если вы действительно не можете изменить базовые типы, создайте подкласс для каждого из них, который реализует ваш общий интерфейс.

Да, вы можете сделать это с помощью отражения ... но вам на самом деле не следует этого делать, потому что в итоге вы получитехрупкий, подвержен ошибкам, код.

0 голосов
/ 06 июля 2011

Два идентичных или похожих объекта из разных пространств имен?

У вас есть:

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 

Cheers.

0 голосов
/ 06 июля 2011
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);
 }
}

от здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...