如何在代码中实现这样的实体?
不成功的尝试:
枚举
我尝试了这样的枚举:
enum Animals { Frog,Duck,Otter,Fish }
其他代码段将打开枚举.然而,这导致了丑陋的切换代码,分散了逻辑和problems with comboboxes.没有很好的方法来列出所有可能的动物.序列化虽然很好.
子类
我还想过每个动物类型在哪里是公共基础抽象类的子类.但是,对于所有动物来说,Swim()的实现是相同的,因此它没有多大意义,可串行化现在是一个大问题.由于我们代表一种动物类型(物种,如果你愿意),每个应用程序应该有一个子类的实例,当我们使用序列化时,这很难维护.
public abstract class AnimalBase { string Name { get; set; } // user-readable double Weight { get; set; } Habitat Habitat { get; set; } public void Swim(); { /* swim implementation; the same for all animals but depends uses the value of Weight */ } } public class Otter: AnimalBase{ public Otter() { Name = "Otter"; Weight = 10; Habitat = "North America"; } } // ... and so on
简直太糟糕了.
静态字段
This blog post给了我一个解决方案的想法,其中每个选项都是类型中静态定义的字段,如下所示:
public class Animal { public static readonly Animal Otter = new Animal { Name="Otter",Weight = 10,Habitat = "North America"} // the rest of the animals... public string Name { get; set; } // user-readable public double Weight { get; set; } public Habitat Habitat { get; set; } public void Swim();
}
那会很棒:你可以像枚举一样使用它(AnimalType = Animal.Otter),你可以轻松添加所有已定义动物的静态列表,你有一个合理的地方可以实现Swim().通过使财产制定者受到保护可以实现不变性.但是存在一个主要问题:它打破了可串行化.序列化的Animal必须保存它的所有属性,并且在反序列化时它会创建一个Animal的新实例,这是我想要避免的.
是否有一种简单的方法可以使第三次尝试工作?有关实施此类模型的更多建议吗?
解决方法
编辑:这是一些示例代码:
public class Animal { public string Name { get; private set; } public double Weight { get; private set; } public Habitat Habitat { get; private set; } internal Animal(string name,double weight,Habitat habitat) { this.Name = name; this.Weight = weight; this.Habitat = habitat; } public void Swim(); } public class SerializableAnimal { public string Name { get; set; } public double Weight { get; set; } public SerializableHabitat Habitat { get; set; } //assuming the "Habitat" class is also immutable } public static class AnimalSerializer { public static SerializableAnimal CreateSerializable(Animal animal) { return new SerializableAnimal {Name=animal.Name,Weight=animal.Weight,Habitat=HabitatSerializer.CreateSerializable(animal.Habitat)}; } public static Animal CreateFromSerialized(SerializableAnimal serialized) { return new Animal(serialized.Name,serialized.Weight,HabitatSerializer.CreateFromSerialized(serialized.Habitat)); } //or if you're using your "Static fields" design,you can switch/case on the name public static Animal CreateFromSerialized(SerializableAnimal serialized) { switch (serialized.Name) { case "Otter" : return Animal.Otter } return null; //or throw exception } }
那么序列化的应用程序逻辑可能如下所示:
Animal myAnimal = new Animal("Otter",10,"North America"); Animal myOtherAnimal = Animal.Duck; //static fields example SerializableAnimal serializable = AnimalSerializer.CreateSerializable(myAnimal); string xml = XmlSerialize(serializable); SerializableAnimal deserialized = XmlDeserializer<SerializableAnimal>(xml); Animal myAnimal = AnimalSerializer.CreateFromSerialized(deserialized);
重申一下,SerializableAnimal类和用法仅用于需要序列化/反序列化的应用程序的最后一层.其他一切都适用于你的不可变的Animal类.
EDITx2:此托管分离的另一个主要好处是您可以处理代码中的旧版更改.例如,你有一个Fish类型,它相当广泛.也许你以后将它分成鲨鱼和金鱼,并决定你所有的旧鱼类应该被认为是金鱼.通过这种序列化的分离,您现在可以检查任何旧Fish并将它们转换为Goldfish,而直接序列化将导致异常,因为Fish不再存在.