C # - Как скопировать / создать объект как потомок - PullRequest
4 голосов
/ 06 марта 2010

Это проще объяснить на примере. Учитывая эти два класса:

public class MyClassA
{
    public String Property_A { get; set; }
    public String Property_B { get; set; }
    public String Property_C { get; set; }
    public String Property_D { get; set; }
    ...
    public String Property_Y { get; set; }
}

public class MyClassB: MyClassA
{
    public String Property_Z { get; set; }
}

Предположим, я полностью создал экземпляр MyClassA (со всеми свойствами от A до Y). Затем мне нужно сделать экземпляр MyClassB, который точно такой же, как мой экземпляр MyClassA, но с заполненным Property_Z (с пользовательским значением, конечно). Как я могу это сделать?

Это не работает (выбрасывает и исключение Invalid Cast):

MyClassB myInstanceB = (myClassB) myInstanceA;
myInstance.Property_Z = myCustomValue;

Мне не нужно было делать ничего подобного со времен C ++, и я в тупике.

Есть идеи?


ОБНОВЛЕНИЕ: я нашел решение моей проблемы в том, как я создаю экземпляры. Это ниже. Я не пометил его как ответ, потому что он не совсем соответствовал моему вопросу.

Ответы [ 7 ]

5 голосов
/ 06 марта 2010

Экземпляр, который вы создали, является MyClassA. Это его тип времени выполнения, а не MyClassB. Вы не можете привести MyClassA экземпляр к MyClassB во время выполнения, потому что MyClassB является более конкретным типом, чем MyClassA.

Вам необходимо создать новый экземпляр MyClassB. Один из способов исправить это - создать конструктор, который принимает MyClassA, например

public class MyClassB : MyClassA
{
    public MyClassB(MyClassA a, string z)
    {
        this.PropertyA = a.PropertyA;
        this.PropertyB = a.PropertyB;
        // etc.
        this.PropertyZ = z;
    }

    public string PropertyZ { get; set; }
}
2 голосов
/ 06 марта 2010

Похоже, вы ищете бесплатный конструктор копирования.C # не предоставляет один (http://msdn.microsoft.com/en-us/library/ms173116%28VS.80%29.aspx), но вы можете сделать это довольно легко с Object.MemberwiseClone или сериализатором BinaryFormatter (http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx).. Позаботьтесь, чтобы знать, хотите ли вы мелкую копию или глубокую копию.

2 голосов
/ 06 марта 2010

Простой ответ:

public class MyClassA 
{ 
    public String Property_A { get; set; } 
    public String Property_B { get; set; } 
    public String Property_C { get; set; } 
    public String Property_D { get; set; } 
    ... 
    public String Property_Y { get; set; } 
} 

public class MyClassB: MyClassA 
{ 
    public MyClassB(MyClassA copy)
    {
        Property_A = copy.PropertyA;
        Property_B = copy.PropertyB;
        ...
    }
    public String Property_Z { get; set; } 
} 

Используйте это так:

MyClassB o = new MyClassB(instanceOfMyClassA);
o.Property_Z = whatever;
2 голосов
/ 06 марта 2010

Вы можете использовать Reflection для копирования свойств базового класса, как показано здесь .

 public void Update(MyObject o)
    {
        MyObject copyObject = ...
        Type type = o.GetType();
        while (type != null)
        {
            UpdateForType(type, o, copyObject);
            type = type.BaseType;
        }
    }


    private static void UpdateForType(Type type, MyObject source, MyObject destination)
    {
        FieldInfo[] myObjectFields = type.GetFields(
            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

        foreach (FieldInfo fi in myObjectFields)
        {
            fi.SetValue(destination, fi.GetValue(source));
        }
    }
1 голос
/ 06 марта 2010

Вы можете определить явное или неявное приведение из MyClassA в MyClassB и использовать предоставленный вами синтаксис.

public class MyClassB : MyClassA
{
    public String Property_Z { get; set; }

    public static explicit operator MyClassB(MyClassA a)
    {
        MyClassB b = new MyClassB();
        b.Property_A = a.Property_A;
        /* ... */
        b.Property_Y = a.Property_Y;
        return b;
    }
}
0 голосов
/ 06 марта 2010

Вот что я в итоге сделал:

Я создал свой метод, который создает и настраивает все свойства (AY), использующие параметры типа.Это выглядит следующим образом:

public T MakeAMyClass<T>(AnotherClass 
where T: MyClassA : new()
{
   T returnValue = new T();
   T.Property_A = somethingToSetFrom.MakeAPropertyA();
   // Fill in the rest of the properties
}

Поскольку параметр типа может быть типом, который является потомком ограничения, я могу передать объекты MyClassB и получить их так же, как myClassA.

Тогда я могу сделать любой из них по мере необходимости.

MyClassA myInstanceA = MakeAMyClass<MyClassA>(somethingToSetFrom);
MyClassB myInstanceB = MakeAMyClass<MyClassB>(somethingToSetFrom);
myInstanceB.Property_Z = someotherValue;

Позволяет мне не создавать метод для копирования всех свойств из MyClassA в MyClassB.

0 голосов
/ 06 марта 2010

Как насчет:

  1. Создайте базовый класс, который реализует IClonable и имеет все строковые свойства от A до D и Z.
  2. Создайте экземпляр этого класса для MyClassA.
  3. Создание экземпляра MyClassB путем клонирования MyClassA.
  4. Установка свойства Z в MyClassB.
...