2015-08-20 101 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; 
    } 
} 

这工作,但我失去了所有类型的安全,难道还有比构造函数注入一个更好的解决方案?

感谢,

编辑:这是一个真实的例子。我有它返回3个对象第三方库调用:

  • GetPageByIdResult
  • GetPagesByParentIdResult
  • GetPagesByDateResult

(这些都是自动生成的类从服务引用和属性是非常相同)

而不是处理这三个对象,我想处理单个PageData对象或它们的集合。

+0

看起来像一个奇怪的类,为什么猫和狗不是从动物继承的? –

+0

如果'Dog'和'Cat'继承自'Animal',则可以尝试:'public Animal(Anima data)' –

+0

复制基础/父对象上的构造函数绝对不应该满足派生类型的所有情况。另外,如果'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

我目前在该DogCat类的 第三方组件存在的情况下,我无法修改它们

我建议基于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序列化程序,以确保类型安全。

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