我正在努力寻找具有以下属性的数据收集的最佳方式:
- 不可变/只读
- 键控访问而不是字符串访问(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;
}
}