C#-具有类型安全性且无重复的可迭代数据类型



我正在努力寻找具有以下属性的数据收集的最佳方式:

  • 不可变/只读
  • 键控访问而不是字符串访问(ImmutableDictionary将不起作用,打字错误只会在运行时暴露(
  • 可枚举(可以迭代(
  • 值的类型强制执行

到目前为止我研究过的一些东西:

普通类:

class Foo
{
public static readonly BarType Item1 = new SubTypeA(Scope: "Global", chickens: 4);
public static readonly BarType Item2 = new SubTypeB(scope: "Local", chickens: 37);
public static IEnumerable<BarType> AllItems()
{
yield Var1;
yield Var2;
}
public static BarType fetch(int idx)
{
return AllItems().ToList()[idx]
}
}

这种方法的问题是,开发人员可能会错误地添加新的Item3,但忘记将显式yield语句添加到AllItmes

我尝试的另一种方法是使用反射:

class Foo
{
public static readonly BarType Item1 = new SubTypeA(Scope: "Global", chickens: 4);
public static readonly BarType Item2 = new SubTypeB(scope: "Local", chickens: 37);
public static IEnumerable<BarType> AllItems()
{
return typeof(Foo).GetFields().Select(f => (BarType)f.GetValue(typeof(Foo)))
}
public static BarType Fetch(int idx)
{
return AllItems().ToList()[idx]
}
}

这里的问题是显式演员阵容。添加另一个不属于BarType子类的字段将在运行时再次中断。

我还没有找到更好的解决方案,并且仍在使用带字符串访问的ImmuntableDictionary。

有什么建议吗?速度并不令人担忧。


回答问题

(1(按键加速可能不是最好的术语。也许"点访问";更好吗?

我的意思是这个Foo["bar"]->编译器无法验证"bar"

而如果bar不是Foo上的字段或方法,则Foo.bar将显示错误

NamedTuple具有此属性,但不可迭代。

(2(ImmutableDictionary不需要字符串键。我还可以使用哪些键来强制执行1:1映射(每个键必须恰好匹配一个字典值(?

如果我理解您的需求,您希望能够枚举特定类型的所有字段。我会创建一次字段列表:

class Foo
{
public static readonly BarType Item1 = new SubTypeA(Scope: "Global", chickens: 4);
public static readonly BarType Item2 = new SubTypeB(scope: "Local", chickens: 37);
private static List<BarType> _bars =
typeof(Foo).GetFields()
.Where(f => f.FieldType==typeof(BarType)
.Select(f => (BarType)f.GetValue(typeof(Foo)))
.ToList();
public static IEnumerable<BarType> AllItems()
{
return _bars;
}
public static BarType Fetch(int idx)
{
return _bars[idx];
}
}

现在唯一的风险是开发人员在_bars声明之后添加BarType,因为静态成员是按照它们在类中出现的顺序初始化的。您可以通过一个严厉的注释和一个单元测试来减轻这种风险,该单元测试在初始化后获取所有BarType字段,并将其与AllItems()进行比较。

怎么样

public class SafeDict {
public enum Keys {
K1,K2,K3
}
private Dictionary<Keys, BarType> _dict = new Dictionary<Keys, BarType>() {
{Keys.K1, new BarType() },
{Keys.K2, new BarType() },
};
public BarType Get(Keys key) {
return _dict[key];
}
public IEnumerable<BarType> GetAll() {
return _dict.Values;
}
}

最新更新