2009-08-13 3 views
14

Я уже много лет работаю с C#, но просто сталкиваюсь с этой проблемой, которая меня бросает, и я действительно даже не знаю, как задать вопрос, так, на примере!Интерфейс свойства copy в C#

public interface IAddress 
{ 
    string Address1 { get; set; } 
    string Address2 { get; set; } 
    string City { get; set; } 
    ... 
} 

public class Home : IAddress 
{ 
    // IAddress members 
} 

public class Work : IAddress 
{ 
    // IAddress members 
} 

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

Спасибо!

+0

Думаю, это может быть дубликат http://stackoverflow.com/questions/563253/c-generic-copy-constructor. Если ничего другого, он должен ответить на ваш вопрос. –

ответ

2

Для этого нет ни одного лайнера.

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

BTW COBOL имеет заявление для этого: ПЕРЕМЕЩЕНИЕ КОРРЕСПОНДЕННОГО ДОМА ДЛЯ РАБОТЫ.

12

Вы можете создать метод расширения:

public static void CopyAddress(this IAddress source, IAddress destination) 
{ 
    if (source is null) throw new ArgumentNullException("source"); 
    if (destination is null) throw new ArgumentNullException("destination"); 

    //copy members: 
    destination.Address1 = source.Address1; 
    //... 
} 
+0

Мне очень нравится это решение. Благодаря! – opedog

+2

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

1

Вам нужно будет создать метод, чтобы сделать это

public void CopyFrom(IAddress source) 
{ 
    this.Address1 = source.Address1; 
    this.Address2 = source.Address2; 
    this.City = source.city; 
} 
+0

Это хрупкий метод, который может сломаться при добавлении новых свойств. – plinth

+0

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

0

Вы можете иметь конструктор по каждому классу принимающего IAddress и внедрили пользователей заполненный внутри.

например

public WorkAddress(Iaddress address) 
{ 
    Line1 = IAddress.Line1; 
    ... 
} 

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

НТН,

Dan

0

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

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

2

Я не верю, что для этого есть готовое к языку решение (все свойства должны иметь геттеры и сеттеры).

Вы можете создать адрес как абстрактный класс с помощью метода Копировать (адрес).

В качестве альтернативы, вы можете сделать Home и Work, чтобы иметь IAddress, и не расширять его. Затем копия будет немедленной.

4

Jimmy Bogard's AutoMapper очень полезен для такого рода операции отображения.

+0

У Apache Commons была библиотека под названием «BeanUtils», которую я использовал для разработки на Java. То, что Мартиньо Фернандес предлагает, является ближайшей соответствующей библиотекой .net. –

18

Вот один из способов сделать это, что не имеет ничего общего с интерфейсами:

public static class ExtensionMethods 
{ 
    public static void CopyPropertiesTo<T>(this T source, T dest) 
    { 
     var plist = from prop in typeof(T).GetProperties() where prop.CanRead && prop.CanWrite select prop; 

     foreach (PropertyInfo prop in plist) 
     { 
      prop.SetValue(dest, prop.GetValue(source, null), null); 
     } 
    } 
} 

class Foo 
{ 
    public int Age { get; set; } 
    public float Weight { get; set; } 
    public string Name { get; set; } 
    public override string ToString() 
    { 
     return string.Format("Name {0}, Age {1}, Weight {2}", Name, Age, Weight); 
    } 
} 

static void Main(string[] args) 
{ 
    Foo a = new Foo(); 
    a.Age = 10; 
    a.Weight = 20.3f; 
    a.Name = "Ralph"; 
    Foo b = new Foo(); 
    a.CopyPropertiesTo<Foo>(b); 
    Console.WriteLine(b); 
} 

В вашем случае, если вы хотите только один набор свойств интерфейса для копирования вы можете сделать это:

((IAddress)home).CopyPropertiesTo<IAddress>(b); 
+1

Вы должны, вероятно, придерживаться ограничения там - где T: IAddress. Затем вы также можете кэшировать поиск Reflection, а не делать это для каждого вызова, и все же избегать необходимости обновления метода, если интерфейс изменится. –

+0

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

+1

Ваш код будет разбит во время выполнения, если 'source' и' dest' - это разные типы, которые они задают в исходном вопросе. Вы можете исправить это, получив список свойств из 'T', а не из' source'. Например: 'var plist = from prop в typeof (T) .GetProperties(), где prop.CanRead && prop.CanWrite select prop;' – LukeH