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

StackOverflow https://stackoverflow.com/questions/303555

Вопрос

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

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;

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

Это было полезно?

Решение

" Не могли бы вы привести пример того, как я могу это сделать (или, по крайней мере, указать мне, какие методы следует использовать)? Кажется, я не могу найти их в MSDN " & # 8211; Джейсон Бейкер

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

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

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

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

Другие советы

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

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; и наоборот.

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

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

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

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

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

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

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

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

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

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

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

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

class MyClass : ICloneable
{
public MyClass()
{

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

return mc;
}

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

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

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

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;
        }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top