我想定义一个具有有限元素集的值类型,这些元素又是运行时动态定义的列表的元素(例如,来自数据库)。
有了这个,我希望能够在动态列表上强制类型安全(很好,有点),而在编译时没有任何可用的值。然后,我可以在代码中将新类型用作属性,作为方法等中的返回值。
(注意-这并不是真正的“安全”类型,即我所追求的编译时检查,而是能够在概念上识别方法和属性中“这种类型的值”的能力-以便更好地理解和理解代码。)
伪代码:
type Currency = ["USD", "EUR", "GBP"];
Currency cur = new Currency();
cur = "CAD"; // must throw an exception
Currency.Add("CAD");
cur = "CAD"; // now it would NOT throw an exception
它有点像“ String”的子类,但是String是密封的类,不能从中派生。
您还可以将其视为定义为从列表中返回“ ValueOf”函数的类型。但这并没有给我提供在C#中定义类型的方法。
有什么合理的方法可以做我想要的吗?
答案 0 :(得分:5)
请注意,当您谈论类型安全时,大多数C#开发人员都会自动假定您正在谈论编译时检查。由于这不是您要的内容,因此有些人被推迟了。
您要执行的实际上不是语言功能,而是可以通过简单的编程概念来完成的事情:
void Main()
{
Currency.Add("USD", "EUR", "GBP");
Currency cur = new Currency("CAD"); // must throw an exception
Currency.Add("CAD");
cur = new Currency("CAD"); // now it would NOT throw an exception
}
public class Currency{
private static List<string> availableValues = new List<string>();
public static void Add(params string[] values){
foreach (var value in values)
{
availableValues.Add(value);
}
}
public Currency(string value){
if(!availableValues.Contains(value)){
throw new ArgumentOutOfRangeException(nameof(value), value + " is not a valid Currency");
}
this.Value = value;
}
public string Value{get;}
public override string ToString() => Value;
}
此代码假定您将在启动时注册所有可用货币。如果您希望在积极使用该类的同时添加新的值,则可以使用ConcurrentDictionary<>
之类的东西来代替List<>
。
可以创建一个隐式转换运算符,以便Currency cur = "CAD";
语法起作用。您还可以创建另一个转换运算符,以便将Currency自动转换为String(而不需要访问Value属性)。
public static implicit operator Currency(string name) =>
new Currency(name);
public static implicit operator string(Currency currency) =>
currency.Value;