【问题标题】:Create overrideable enum in parent class在父类中创建可覆盖的枚举
【发布时间】:2018-04-03 10:53:21
【问题描述】:

我想创建一个嵌套结构,其中每个类都代表一个国家,继承同一个父类Country。每个子类都应该有一个代表不同状态的枚举States

目标是能够选择一个国家,然后是其中一个州。

内容将保存到字典Dictionary<Tuple<string, Type>, object> 中,其中Types 将是CountryCountry.States

我尝试创建一个abstract class 和一个名为Statesabstract class,但这不起作用,因为它是一个类型定义。

有什么解决办法吗?

public abstract class Country
{
    public abstract enum States { get; }
}

public class CountryA : Country
{
    public new enum States
    {
        StateA,
        StateB,
        StateC,
    }
}

【问题讨论】:

  • 我喜欢早上 X Y 的气味。认真,虽然你不能。您可能希望的最好结果是通过 int 访问各个级别的枚举,或者通过某种 adhock 实现进行某种反射
  • 使用枚举来存储一个国家的状态听起来很糟糕。
  • @crazyGamer 使用类来表示国家更糟糕。 OP:你真的会有超过 200 个类和数千个枚举吗?每次国家/地区发生变化时,您会重新构建您的应用程序吗?他们的州呢?
  • 我想知道public class Country { public string CountryName;}public class State : Country { public string StateName; } 是否更适合。但我不喜欢它。无论如何,为每个国家/地区设置多个课程听起来很难维持。
  • 伙计们,这只是一个大学项目。我只想存储一些示例:D(顺便说一句,项目是关于插件的)

标签: c# inheritance enums


【解决方案1】:

您的设计有缺陷,您需要创建一个带有属性的 Country 类,例如public string[] States { get; set; }.

然后创建Country 类的实例(对象),每个实例(对象)都将States 设置为所需的项目:

var usa    = new Country { Name = "USA",    States = new[] { "Alabama", ... } };
var canada = new Country { Name = "Canada", States = new[] { ... } };
// etc

【讨论】:

  • 这些实例可以是类本身的静态公共成员,然后是nearly as enum
  • 而不是string[] 我建议HashSet<string>
【解决方案2】:

你有几个选择:

您可以在运行时创建一个枚举(请参阅此处:Dynamically create an enum),但我认为这不适合您的需求,因为我想您正在使用枚举路线以便于编码而不是还有什么。

您可以实现类型安全的枚举模式(请参阅此处:typesafe enum pattern),但这只是为了在编写其余逻辑时使用模仿枚举的设计的能力。

我的建议是使用字典并在实例化时从设置文件或外部数据源构建“状态”。毕竟,国家及其州/城市/等确实会不时更改名称。将自己锁定在一个像你的目标那样的硬编码情况中不会支持这种未来的变化。

祝你好运!

[根据 camilo-terevinto 的回复编辑]

【讨论】:

  • "你的目标是做不到" 请证明这是真的。当然有可能,只是需要很长时间,甚至不值得
  • @CamiloTerevinto,当然,可以滥用类型安全枚举模式来满足 OP 的需求。我忘记了。
【解决方案3】:

虽然我当然同意您的设计很可能存在缺陷,因为您需要数百个类和枚举,但我完全不同意“不可能”的其他答案。

当然可以使用泛型 (while keeping in mind you cannot restrict entirely to Enums):

public abstract class Country<TStates> 
    where TStates: struct, IConvertible, IFormattable, IComparable
{
    public abstract TStates[] States { get; }
}

public enum UnitedStatesStates
{
    WhoCares, WhoCares2
}

public class UnitedStatesCountry : Country<UnitedStatesStates>
{
    public override UnitedStatesStates[] States { get; }
}

现在,我非常怀疑这在(不那么长的)期限内是否有用。

【讨论】:

  • 您可以使用一些 IL 对其进行更多限制,但我不确定他的用例是否与泛型实现匹配。无论如何我都会给你一个赞成票,因为今晚的积分来之不易
【解决方案4】:

您要求使 enum 可继承,如果您不使用 enum,而是使用具有 static public 成员的类(可以被继承并具有不同的成员集),这是可能实现的每种类型)。它的行为几乎与枚举一样:

public class Country1
{
    public static State State1 { get; } = new State("State 1");
    public static State State2 { get; } = new State("State 2");
    ...
}

Country1.State1 是什么应该很清楚了吧? State 可以是一个比 string 更复杂的对象。如您所见,它不需要继承,因为国家/地区将州定义为不同的成员。

您可以遵循相同的原则来实现长对象:Planet.Continent.Country.State.Province.Town.Street.Hause..


你说

内容将保存到字典Dictionary&lt;Tuple&lt;string, Type&gt;, object&gt; 中,其中类型为CountryCountry.States

不要。这些是不同的类型,这是一个糟糕的选择。如果您需要枚举(查找)状态,则只需将另一个成员添加到 Country

public static IEnumerable<State> States
{
    get
    {
        yield return State1;
        yield return State2;
        ...
    }
}

那么搜索可以是一个简单的linq:

var stateAInCountry1 = ...Countries.OfType<Contry1>().Single().States.Single(o => o.Name == "A");
var countriesWithStateA = ...Countries.Where(o => o.States.Any(o => o.Name == "A"));

不确定您通过引入字典解决了什么问题,但如果您提供了一种轻松迭代的方法,您可以使用 proper 键初始化其他数据结构。

【讨论】:

    【解决方案5】:

    除了编译器提醒您定义这些不同的 (!) 枚举之外,我还不太清楚,如果您还想实现其他任何目标。

    实际上,它们一开始就没有任何共同点,因此编译器和您都无法从该合约中获得任何优势。

    你可以做的就是将它声明为

    public abstract string[] States {get;}
    

    并从您在派生类中定义的各个枚举中获取这些字符串。那么常见的事情可能是您希望字符串结果用于提供信息或其他目的。

    【讨论】:

      猜你喜欢
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多