Использование интерфейса для преобразования объекта из одного типа в другой? - PullRequest
9 голосов
/ 20 ноября 2008

Предположим, у меня есть два класса с одинаковым интерфейсом:

interface ISomeInterface 
{
    int foo{get; set;}
    int bar{get; set;}
}

class SomeClass : ISomeInterface {}

class SomeOtherClass : ISomeInterface {}

Предположим, у меня есть экземпляр ISomeInterface, который представляет SomeClass. Есть ли простой способ скопировать это в новый экземпляр SomeOtherClass, не копируя каждый член вручную?

ОБНОВЛЕНИЕ: Для записи, я не пытаюсь привести экземпляр SomeClass в экземпляр SomeOtherClass. Я хотел бы сделать что-то вроде этого:

ISomeInterface sc = new SomeClass() as ISomeInterface;
SomeOtherClass soc = new SomeOtherClass();

soc.foo = sc.foo;
soc.bar = soc.bar;

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

Ответы [ 9 ]

9 голосов
/ 20 ноября 2008

Вы можете создать неявные операторы в каждом классе, чтобы выполнить преобразование для вас:

public class SomeClass
{
    public static implicit operator SomeOtherClass(SomeClass sc)
    {
        //replace with whatever conversion logic is necessary
        return new SomeOtherClass()
        {
            foo = sc.foo,
            bar = sc.bar
        }
    }

    public static implicit operator SomeClass(SomeOtherClass soc)
    {
        return new SomeClass()
        {
            foo = soc.foo,
            bar = soc.bar
        }
    }
    //rest of class here
}

, а затем SomeOtherClass soc = sc; и наоборот будет работать.

6 голосов
/ 20 ноября 2008

Разве интерфейс не должен делать это? Вы что-то делаете с конкретной реализацией SomeOtherClass? Вместо использования конкретной реализации используйте интерфейс, и не должно иметь значения, используете ли вы класс SomeClass или SomeOther.

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

   public ISomeInterface CopyValues(ISomeInterface fromSomeClass, ISomeInterface toSomeOtherClass)
   {
    //copy properties here
    return toSomeOtherClass;
    }

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

4 голосов
/ 20 ноября 2008

Проверьте ответ Джо для решения Reflection.

Я предполагаю, что вы используете Visual Studio.

Вам знакомы сочетания клавиш ctrl + shift + r и ctrl + shift + p? Если нет, Ctrl + Shift + R начинает / заканчивает запись макроса нажатия клавиш. Ctrl + Shift + P воспроизводит записанный макрос.

Что я сделал, когда установил много свойств, так это скопировал объявления свойств туда, где я хочу, чтобы они были установлены, и записал макрос для преобразования объявления в оператор set и перемещения курсора на следующую строку. затем я просто играю, пока не выполню все установленные операторы.

4 голосов
/ 20 ноября 2008

Reflection ... перебирает каждое свойство и устанавливает его для соответствующего свойства другого объекта.

3 голосов
/ 20 ноября 2008
   ISomeInterface sc = new SomeClass() as ISomeInterface;
   SomeOtherClass soc = new SomeOtherClass();
   foreach (PropertyInfo info in typeof(ISomeInterface)
                                     .GetProperties(BindingFlags.Instance
                                                     |BindingFlags.Public))
   {
       info.SetValue(soc,info.GetValue(sc,null),null);
   }
3 голосов
/ 20 ноября 2008

«Не могли бы вы дать мне пример того, как я могу это сделать (или, по крайней мере, указать мне на правильные методы, которые нужно использовать)? Я не могу найти их в MSDN» - Джейсон Бейкер

Джейсон, что-то вроде следующего:

var props = typeof(Foo)
            .GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (PropertyInfo p in props)
{
     // p.Name gives name of property
}

Я бы предложил написать инструмент для выделения кода, необходимого для конструктора копирования, в отличие от рефлективного выполнения во время выполнения - что было бы менее производительным.

3 голосов
/ 20 ноября 2008

не сработает ли это?

class MyClass : ICloneable
{
public MyClass()
{

}
public object Clone() // ICloneable implementation
{
MyClass mc = this.MemberwiseClone() as MyClass;

return mc;
}

Вам нужно только позвонить: MyClass.Clone ().

3 голосов
/ 20 ноября 2008

Нет, для прозрачного преобразования (приведения) объекта из одного типа в другой, базовый конкретный класс объекта, который у вас есть, должен наследовать от класса, к которому вы пытаетесь его привести, даже если они оба дополняют одно и то же интерфейс.

Подумайте об этом, для реализации одного и того же интерфейса все два объекта должны иметь одно и то же подмножество сигнатур методов. Они могут не иметь (вероятно, не иметь) даже одинаковых свойств или полей данных.

2 голосов
/ 08 декабря 2010

Мне понравилось следующее, и он очень хорошо работает для преобразования из одного объекта в другой, используя неявный оператор:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello");
            ExecutionReport er = new ExecutionReport("ORDID1234",3000.43,DateTime.UtcNow);
            Order ord = new Order();
            ord = er;
            Console.WriteLine("Transferred values are : " + er.OrderId + "\t" + ord.Amount.ToString() + "\t" + ord.TimeStamp.ToString() + "\t");
            Console.ReadLine();
        }
    }


    public  class Order
    {
        public string OrderId { get; set; }
        public double Amount { get; set; }
        public DateTime TimeStamp { get; set; }
        public static implicit operator ExecutionReport(Order ord)
        {
            return new ExecutionReport()
            {
                OrderId = ord.OrderId,
                Amount = ord.Amount,
                TimeStamp = ord.TimeStamp
            };
        }
        public static implicit operator Order(ExecutionReport er)
        {
            return new Order()
            {
                OrderId = er.OrderId,
                Amount = er.Amount,
                TimeStamp = er.TimeStamp
            };
        }

        public Order()
        { }
    }

    public  class ExecutionReport
    {
        public string OrderId { get; set; }
        public double Amount { get; set; }
        public DateTime TimeStamp { get; set; }
        public ExecutionReport() { }
        public ExecutionReport(string orderId,double amount, DateTime ts)
        {
            OrderId = orderId; Amount = amount; TimeStamp = ts;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...