绝对仍然是培训程序员,但尝试为我的项目做些事情,然后转圈。请在设置课程方面寻求任何指导。我正在开发供他人通过.dll程序集使用的代码。
让我只描述一个简单的类(使用Base类),它具有一些属性,称为Car。这些就是我要达到的目标的要求:
1)可以创建Car类的实例。用户实例化的Car对象的所有属性都应该可以更改。
2)能够为他们提供3个预生成的Car对象供他们直接使用。怎么样:本田CRV,丰田普锐斯,日产流氓
3)应该锁定预生成的汽车(本田CRV,丰田普锐斯,日产Rogue)(只读?)。甚至基类Transportation中的属性也应该是只读的。
实现此目标的最佳方法是什么?我是否使用静态属性?我是否使用readonly修饰符?我是否创建一个名为HondaCRV的新类(例如)并将Car用作基类?然后在那里使事物变为只读状态?我该如何公开和私有(或受保护)?还是我只是创建一个名为“汽车”的新类,将我的3个预生成的汽车(作为属性)暴露出来?
我只是不知道什么是最好的方法,哪一种方法将为我的大会消费者提供最好的体验。我尝试了几件事,但是我接近了,但是我永远无法获得“只读”才能传播到基类。
请原谅我可能在示例代码中写的任何不良做法。我仍然是接受培训的C#程序员。
在此先感谢您能为我提供的任何帮助,并帮助您理解我的帖子。我很高兴(很兴奋)学习并采纳您可能对我有的任何想法。而且,我也非常乐于澄清任何事情。我尽力表达了自己的要求。
阿玛尔
enum Terrain
{
Land,
Water,
Air
}
class Transportation
{
private Terrain terrainType;
public Terrain TerrainType
{
get { return terrainType; }
set { terrainType = value; }
}
}
class Car:Transportation
{
private string mfg;
private string model;
public string Mfg
{
get { return mfg; }
set { mfg = value; }
}
public string Model
{
get { return model; }
set { model = value; }
}
public Car(string Manufacturer, string CarModel)
{
Mfg = Manufacturer;
Model = CarModel;
TerrainType = Terrain.Land;
}
}
答案 0 :(得分:2)
这就是我要做的。在现实生活中,我可能在数据库中有一个Manufacturer
表和一个Model
表,它们之间具有外键关系。在这里,我使用enum
和Dictionary
我将枚举用于制造商。这是一个不会经常更改的列表(在过去十年左右的时间里,我可以将Genesis和Tesla视为新的制造商):
public enum CarManufacturer
{
Acura,
BMW,
Buick,
//fill in more
Honda,
Nissan,
Tesla,
Toyota,
//etc
}
我独自留下了您的“地形”枚举:
public enum Terrain
{
Land,
Water,
Air
}
我将您的Transportation
类更改为abstract
(即,不可实例化),并将TerrainType
属性设置为只读。它只能在构造函数中设置。我还只提供了一个非默认的构造函数(因此必须设置该属性):
//This is abstract, no one can instantiate one,
//only subclasses of this type can be constructed
public abstract class Transportation
{
//this is read-only and must be set at construction time
public Terrain TerrainType { get; }
protected Transportation(Terrain terrainType)
{
TerrainType = terrainType;
}
//you probably want some methods (example, Move). You can declare them "abstract"
}
对汽车类别的许多更改:
Transportation
构造函数结果如下:
public class Car : Transportation
{
//in real life, this might be stored in a database
private static readonly Dictionary<CarManufacturer, List<string>> CarModels =
new Dictionary<CarManufacturer, List<string>>
{
{CarManufacturer.Acura, new List<string> {"RDX", "NSX", "MDX",}},
{CarManufacturer.BMW, new List<string> {"2Series", "3Series", "etc",}},
{CarManufacturer.Honda, new List<string> {"Civic", "Fit", "CRV", "Pilot",}},
{CarManufacturer.Nissan, new List<string> {"Altima", "Maxima", "Rogue",}},
{CarManufacturer.Toyota, new List<string> {"Corolla", "Prius",}},
};
//these get set at constructor time, they cannot be changed after that
public CarManufacturer Manufacturer { get; }
public string Model { get; }
//you need to call the parameterized base class constructor
public Car(CarManufacturer manufacturer, string model) : base(Terrain.Land)
{
Manufacturer = manufacturer;
if (!ValidateCarModel(manufacturer, model))
{
throw new ArgumentException($"Manufacturer {manufacturer} does not make model: {model}");
}
Model = model;
}
public static bool ValidateCarModel(CarManufacturer manufacturer, string model)
{
if (!CarModels.TryGetValue(manufacturer, out var models))
{
return false;
}
return models.Contains(model);
}
public static IEnumerable<string> ModelsForManufacturer(CarManufacturer manufacturer)
{
if (!CarModels.TryGetValue(manufacturer, out var models))
{
//maybe this should through, but this also makes sense
return new List<string>();
}
//otherwise
return models;
}
}
现在我可以制造一些汽车了。在创建它们之前,我可以测试它们是否有效:
Car CRV, Rogue, Prius;
if (Car.ValidateCarModel(CarManufacturer.Honda, "CRV"))
{
CRV = new Car(CarManufacturer.Honda, "CRV");
}
if (Car.ValidateCarModel(CarManufacturer.Nissan, "Rogue"))
{
Rogue = new Car(CarManufacturer.Nissan, "Rogue");
}
//I know that Toyota makes a Prius, so I just create one. If I mess up, I'll get an exception
Prius = new Car(CarManufacturer.Toyota, "Prius");
我认为这可以满足您的需求,并且很有启发性
请注意,除了制造商枚举之外,如果我使用数据库而不是枚举/字典方法,那么我可能会有大致相同的接口。
答案 1 :(得分:1)
为它们提供3个预生成的Car对象,供他们直接使用
仅添加几个类的实例怎么样?
class Car
{
...
public static readonly List<Car> Instances = new List<Car>()
{
new Car() {Model = "Honda", Name = "CRV"},
new Car() {Model = "Toyota", Name = "Prius"},
new Car() {Model = "Nissan", Name = "Rogue"}
};
}
他们将能够像这样访问它们:
Car car = Car.Instances[0];
答案 2 :(得分:1)
我不知道直接在一个类中做什么的直接方法,但是您可以使用模式组合作为变通方法:不可变和工厂。
首先,您声明ImmutableCar类,它隐藏了这样的基类设置器。
public class ImmutableCar : Car
{
public string Mfg
{
get { return base.Mfg; }
}
public string Model
{
get { return base.Model; }
}
public Terrain TerrainType
{
get { return base.TerrainType; }
}
internal ImmutableCar(string Manufacturer, string CarModel) : base (Manufacturer, CarModel)
{
}
}
第二,在内部构造Car和ImmutableCar类的所有构造函数,因此程序集的用户无法调用它。
internal Car(string Manufacturer, string CarModel)
{
Mfg = Manufacturer;
Model = CarModel;
TerrainType = Terrain.Land;
}
internal ImmutableCar(string Manufacturer, string CarModel) : base (Manufacturer, CarModel)
{
}
第三,创建Factory类,该类实例化所有Car。它通过属性返回ImmutableCar为您提供“只读”汽车。对于可编辑的汽车,它提供了GenerateCar方法。
public static class CarFactory
{
public static ImmutableCar HondaCrv {
get
{
return new ImmutableCar("Honda", "Crv");
}
}
public static Car GenerateCar(string Manufacturer, string CarModel)
{
return new Car(Manufacturer, CarModel);
}
}
最后进行了一些测试。
var landroverDiscovery = CarFactory.GenerateCar("Land Rover", "Discovery 2");
landroverDiscovery.Model = "test"; // Ok
var hondaCrv = CarFactory.HondaCrv;
hondaCrv.Model = "test"; // Produces error