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

C# 协助在C中设置类和对象#,c#,class,oop,object,C#,Class,Oop,Object,毫无疑问,我仍然是一名正在接受培训的程序员,但我正在努力为我的项目做点什么,并且在做一些事情。请在我的课程设置方面寻求指导。我正在开发代码供其他人通过.dll程序集使用 让我描述一个名为Car的简单类(使用基类),它有一些属性。这就是我要达到的目标的要求: 1) 创建类Car实例的能力。用户实例化的汽车对象的所有属性都应该是可更改的 2) 能够为他们提供3个预先生成的汽车对象,供他们开箱即用。本田CRV、丰田普锐斯、日产Rogue怎么样 3) 预生成的汽车(本田CRV、丰田普锐斯、日产Rogue

毫无疑问,我仍然是一名正在接受培训的程序员,但我正在努力为我的项目做点什么,并且在做一些事情。请在我的课程设置方面寻求指导。我正在开发代码供其他人通过.dll程序集使用

让我描述一个名为Car的简单类(使用基类),它有一些属性。这就是我要达到的目标的要求:

1) 创建类Car实例的能力。用户实例化的汽车对象的所有属性都应该是可更改的

2) 能够为他们提供3个预先生成的汽车对象,供他们开箱即用。本田CRV、丰田普锐斯、日产Rogue怎么样

3) 预生成的汽车(本田CRV、丰田普锐斯、日产Rogue)应锁定(只读?)。甚至基类传输中的属性也应该是只读的

实现这一目标的最佳方式是什么?我是否使用静态属性?我是否使用只读修饰符?我是否创建了一个名为Hondarv的新类(例如),并使用Car作为基类?然后把里面的东西变成只读的?我应该公开和保密(或保护)什么?或者我只是创建了一个名为“Cars”的新类,它公开了我的3个预生成的汽车(作为属性),而没有其他东西

我只是不知道什么是最好的方法,一个能给我的装配的消费者带来最好体验的方法。我尝试了一些方法,但我无法让“只读”传播到基类

请原谅我在示例代码中编写的任何错误做法。我仍然是一名接受培训的C#程序员

提前感谢您为我提供的任何帮助,并试图理解我的帖子。我很高兴(也很兴奋)能学习并融入你们对我的任何想法。我也非常乐意澄清任何事情。我尽力表达我的要求

阿马尔

为他们提供3个预先生成的汽车对象,供他们开箱即用

只添加几个类的实例怎么样

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");