帮助在C#中设置类和对象

时间:2018-12-28 15:47:39

标签: c# class oop object

绝对仍然是培训程序员,但尝试为我的项目做些事情,然后转圈。请在设置课程方面寻求任何指导。我正在开发供他人通过.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;
    }
}

3 个答案:

答案 0 :(得分:2)

这就是我要做的。在现实生活中,我可能在数据库中有一个Manufacturer表和一个Model表,它们之间具有外键关系。在这里,我使用enumDictionary

我将枚举用于制造商。这是一个不会经常更改的列表(在过去十年左右的时间里,我可以将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