C# 协助在C中设置类和对象#
毫无疑问,我仍然是一名正在接受培训的程序员,但我正在努力为我的项目做点什么,并且在做一些事情。请在我的课程设置方面寻求指导。我正在开发代码供其他人通过.dll程序集使用 让我描述一个名为Car的简单类(使用基类),它有一些属性。这就是我要达到的目标的要求: 1) 创建类Car实例的能力。用户实例化的汽车对象的所有属性都应该是可更改的 2) 能够为他们提供3个预先生成的汽车对象,供他们开箱即用。本田CRV、丰田普锐斯、日产Rogue怎么样 3) 预生成的汽车(本田CRV、丰田普锐斯、日产Rogue)应锁定(只读?)。甚至基类传输中的属性也应该是只读的 实现这一目标的最佳方式是什么?我是否使用静态属性?我是否使用只读修饰符?我是否创建了一个名为Hondarv的新类(例如),并使用Car作为基类?然后把里面的东西变成只读的?我应该公开和保密(或保护)什么?或者我只是创建了一个名为“Cars”的新类,它公开了我的3个预生成的汽车(作为属性),而没有其他东西 我只是不知道什么是最好的方法,一个能给我的装配的消费者带来最好体验的方法。我尝试了一些方法,但我无法让“只读”传播到基类 请原谅我在示例代码中编写的任何错误做法。我仍然是一名接受培训的C#程序员 提前感谢您为我提供的任何帮助,并试图理解我的帖子。我很高兴(也很兴奋)能学习并融入你们对我的任何想法。我也非常乐意澄清任何事情。我尽力表达我的要求 阿马尔 为他们提供3个预先生成的汽车对象,供他们开箱即用 只添加几个类的实例怎么样C# 协助在C中设置类和对象#,c#,class,oop,object,C#,Class,Oop,Object,毫无疑问,我仍然是一名正在接受培训的程序员,但我正在努力为我的项目做点什么,并且在做一些事情。请在我的课程设置方面寻求指导。我正在开发代码供其他人通过.dll程序集使用 让我描述一个名为Car的简单类(使用基类),它有一些属性。这就是我要达到的目标的要求: 1) 创建类Car实例的能力。用户实例化的汽车对象的所有属性都应该是可更改的 2) 能够为他们提供3个预先生成的汽车对象,供他们开箱即用。本田CRV、丰田普锐斯、日产Rogue怎么样 3) 预生成的汽车(本田CRV、丰田普锐斯、日产Rogue
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"}
};
}
我不知道如何在一个类中直接实现您想要的功能,但您可以使用模式的组合作为解决方案:不可变和工厂 首先,声明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)
{
}
第三,创建工厂类,该类实例化所有汽车。它通过properties returns 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
这就是我要做的。在现实生活中,我可能在数据库中有一个
制造商
表和一个模型
表,它们之间有外键关系。在这里,我用一个enum
和一个Dictionary
我使用制造商的枚举。这是一个不会经常改变的列表(在过去十年左右,我可以将Genesis和Tesla视为新的制造商):
我只留下了你的“地形”枚举:
public enum Terrain
{
Land,
Water,
Air
}
我更改了您的Transportation
类,使其成为抽象的
(即不可识别的),并使TerrainType
属性为只读。它只能在构造函数中设置。我还只提供了一个非默认构造函数(因此必须设置该属性):
汽车级别有很多变化:
- 我制作了一个制造模型关系的私有(静态)词典
- 我提供对该词典的有限访问(客户可以获得模型列表,并可以验证特定模型是否由制造商制造)
- 我将制造商属性和模型属性设置为只读-它们都必须在构建时设置
- 我让(唯一)构造函数设置这些属性,并根据需要调用非默认的
构造函数Transportation
Car car = Car.Instances[0];
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;
}
}
我认为这符合你的需要,而且有点启发性
请注意,除了制造商enum之外,如果我使用数据库而不是enum/字典方法,我可以拥有大致相同的界面。可能有一件好事,那就是拥有一个具有三个属性的静态Cars类……因此当用户在Cars中使用我的装配类型时。然后三个预生成的将只出现(洪达克夫、丰田、尼桑罗格)。我能够做到这一点,但遗憾的是,当我使用该类时,我能够更改我不想要的所有属性。嗨,阿玛,谢谢你的提问。请考虑把它张贴,因为它是一个更好的适合在那里,你更可能得到的答案你期待的一种方式之一,这将是使每辆车只读。修改一辆车意味着创建一辆具有所需属性的新车。我同意,让你的类与参数化构造函数保持不变听起来可以解决这个问题。然后,您可以定义一个预先创建的静态汽车池。如果没有其他内容,汽车的品牌和型号不应该是可变的。如果这些属性改变,没有人会认为它是同一辆车。亲爱的德米特里…非常感谢你的职位。我在复习每个人的帖子,研究我不熟悉的C#关键词。我很快会再发。现在,我只想说我真诚的感谢你为我提供了实现和代码。Dmitry!!!是的,一切正常。为了让代码正常工作,我不得不粘贴并做一些小的调整……但事实上,它的工作原理和我想要的完全一样。这太棒了。我真的需要仔细研究每一件事,并将其应用到我的项目中,但你为我指明了一条通往我真正需要的道路。非常感谢你!!!(很高兴帮助你)还有一件事你可能想知道。有一个“new”关键字可以应用于ImmutableCar类中的属性,以避免编译器警告。像这样的“公共新街”
public enum Terrain
{
Land,
Water,
Air
}
//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"
}
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");