2015-08-20 3 views
6

я часто в конечном итоге писать классы так:Сокращения конструктор кода котла плита

public class Animal 
{ 
    public string Colour { get; set; } 
    public int Weight { get; set; } 

    public Animal(Dog data) 
    { 
     this.Colour = data.Colour; 
     this.Weight = data.Weight; 
    } 

    public Animal(Cat data) 
    { 
     this.Colour = data.Colour; 
     this.Weight = data.Weight; 
    } 
} 

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

public class Animal 
{ 
    public string Colour { get; set; } 
    public int Weight { get; set; } 

    public Animal(Cat data){Init(data);} 
    public Animal(Dog data){Init(data);} 

    private void Init(dynamic data) 
    { 
     this.Colour = data.Colour; 
     this.Weight = data.Weight; 
    } 
} 

Это работает, но я теряю все типобезопасность, есть лучшее решение, чем инъекции конструктора?

Спасибо,

Джо

EDIT: Вот реальный пример. У меня есть библиотека третья сторона, которая возвращает 3 объекта называется:

  • GetPageByIdResult
  • GetPagesByParentIdResult
  • GetPagesByDateResult

(Это все автогенерируемая классы из ссылки на службу и свойства в значительной степени идентичны)

Вместо того чтобы иметь дело с этими тремя объектами, я хочу иметь дело с одним объектом PageData или их коллекцией.

+0

Похож на странный класс, почему Кошка и Собака не наследуют от животных? –

+0

, если 'Dog' и' Cat' наследуются от 'Animal', вы можете попробовать:' public Animal (Anima data) ' –

+0

Copy Constructor на базовом/родительском объекте определенно не должен обслуживать все случаи его производных типов. Кроме того, если «Cat» и «Dog», наследующие «Animal», вы можете отлично справиться с одним конструктором с параметром «Animal». – haim770

ответ

3

Вы можете иметь логику в один общем конструкторе, который все остальные конструкторы называют:

public class Animal 
{ 
    public string Colour { get; set; } 
    public int Weight { get; set; } 

    public Animal(Dog data) : this (data.Colour, data.Weight) 
    { 
    } 

    public Animal(Cat data) : this (data.Colour, data.Weight) 
    { 
    } 

    private Animal(string colour, int weight) 
    { 
     this.Colour = colour; 
     this.Weight = weight; 
    } 
} 

Это очень похоже на ваше второе решение, но оно не теряет типобезопасность.

+0

Ах, хорошая идея. Пока это кажется лучшим решением, но я подожду до завтра, прежде чем принимать. – JoeS

1

Если вы не хотите, чтобы класс завалялся таким образом, вы можете попробовать методы расширения?

public static Animal ToAnimal(this Dog item) 
{ 
    return new Animal() {Weight = item.Weight, Colour = item.Colour}; 
} 

public static Animal ToAnimal(this Cat item) 
{ 
    return new Animal() {Weight = item.Weight, Colour = item.Colour}; 
} 
+0

Не могли бы вы также показать общий с интерфейсом, поддерживающим как «Cat», так и «Dog», тогда вы можете показать реальную мощность с помощью методов расширения. –

+0

@CallumLinington. Он упоминает, что они находятся в третьем хотя библиотека. Итак, как мы можем это сделать? –

+0

Адаптер шаблон –

3

Я в настоящее время в ситуации, когда существуют Dog и Cat классов в сборке третьей партии, и я не могу изменить их

Я хотел бы предложить решение Automapper на основе:

public static class AnimalFactory 
{ 
    public static Animal Create<T>(T source) 
     where T : class 
    { 
     Mapper.CreateMap<T, Animal>(); 
     return Mapper.Map<Animal>(source); 
    } 
} 

Использование:

 var catAnimal = AnimalFactory.Create(cat); 
     var dogAnimal = AnimalFactory.Create(dog); 

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

+0

Хмм, это все еще не гарантирует безопасность типа, если у вас нет 1 метода на тип. – DavidG

+0

Не только это, но если есть дополнительные свойства, о которых AutoMapper не знает, это будет сильно зависеть во время выполнения. Поскольку классы живут извне, это может привести к большому количеству конфигурации '.Ignore()', что делает ее менее элегантной. –

+0

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

0

попробуйте использовать json serializer, с этим мы сможем обеспечить безопасность типа.

public class Animal 
    { 
     public string Colour { get; set; } 
     public long Weight { get; set; } 
     public string Name { get; set; } 
     public Animal Create<T>(T anyType) 
     { 
      return GetObject<T, Animal>(anyType); 
     } 
     public K GetObject<T, K>(T type1) 
     { 
      try 
      { 
       var serialized = JsonConvert.SerializeObject(type1); 
       return JsonConvert.DeserializeObject<K>(serialized); 
      } 
      catch (Exception ex) 
      { 
       return default(K); 
      } 
     } 
    } 
    class Program 
    { 
     public static void Main(string[] args) 
     { 
      Animal obj = new Animal(); 
      var animal = obj.Create(new { Colour = "Red", Weight = 100 }); 
      //here you can pass any object, only same name properties will be initialized.. 
      Console.WriteLine(animal.Colour + " : " + animal.Weight); 
      Console.ReadKey(); 
     } 
    } 
Смежные вопросы