我怎么能对文字字符串参数施加约束

How could I put a constraint on a literal string parameter

我不得不说标题太糟糕了,无法描述问题,但这是我唯一能想到的。无论如何,假设我得到了以下枚举:

public enum DocumentType{
      IdCard=0,
      Passport,
      DriversLicense
}

我有一个接受字符串和 return 上面枚举的方法:

public DocumentType GetDocTypeByString(string docType){
    switch (docType)
    {
       case "ID":
         return DocumentType.IdCard;
       case "PASS"
         return DocumentType.Passport;
       //and so on
    }
}

现在,如果传递的字符串不满足任何切换条件怎么办?最愚蠢的事情是将 return 类型设为 object,但几乎没有人会这样做。如果枚举是我的,我会添加一个名为 "None" 和 return 的附加值,以防不匹配,但我无法控制它。然后我想,是否可以将输入限制为某些值。就 C# 而言,我几乎完全确定这是不可能的,但我还是决定问问。在这种情况下你会推荐吗?

不,你不能。通常使用的模式是抛出一个

throw new ArgumentException("docType");

技术上甚至

throw new ArgumentOutOfRangeException("docType");

是正确的,但我从未见过它在 "numeric" 索引之外使用。

例如,Enum.Parse 如果您使用非法值,则抛出 ArgumentException,您的方法似乎与此非常相似。

其他选项是使用 Enum.TryParse 模式:

public static bool TryGetDocTypeByString(string docType, out DocumentType documentType) 
{
    switch (docType)
    {
        case "ID":
            documentType = DocumentType.IdCard;
            return true;
        case "PASS"
            documentType = DocumentType.Passport;
            return true;
    }

    documentType = default(DocumentType);
    return false;
}

您可以使 return 类型可以为 null,然后这样做:

public DocumentType? GetDocTypeByString(string docType){
    switch (docType)
    {
       case "ID":
         return DocumentType.IdCard;
       case "PASS"
         return DocumentType.Passport;
       //and so on
       default: return null;
    }
}

您可以在此处执行几项操作,选择哪一项取决于您希望此方法的输入来自何处。如果得到一个无效的字符串表示程序员犯了错误的场景,最好的办法就是抛出异常。

如果获取无效字符串是一种非常常见(因此并非例外)的情况,例如如果字符串来自用户输入,您可以通过几种可能的方式更改您的方法签名,以向消费者明确表示您的方法可能 return 根本不是一个值:

 public DocumentType? TryGetDocTypeByString(string docType) { ... }
 public bool TryGetDocTypeByString(string docType, out DocumentType result) { ... }

最后,您可以将上述方法结合如下:

public string DocumentType GetDocTypeByString(string docType) 
{
    DocumentType result;
    if(!TryGetDocTypeByString(out result)) throw new ArgumentException("docType");
    return result;            
}

public bool TryGetDocTypeByString(string docType, out DocumentType result) 
{
    // You should probably store this as a static member of your class
    var mapping = new Dictionary<string, DocumentType>() {
         { "ID", DocumentType.IdCard }
         ...
    };

    return mapping.TryGetValue(docType, out result);
}

我会这样写:

public bool GetDocTypeByString(string docType, out DocumentType enumValue){
          return  Enum.TryParse<DocumentType>(docType, true, out enumValue);
}

您可以使用代码合同来指定您期望的确切值。它比 "if throw" 方法更干净。

https://msdn.microsoft.com/en-us/library/dd264808%28v=vs.110%29.aspx

这是一个有点晚的答案,主要是我为了好玩而写的东西,它不优雅或快速,它只是解决问题的方法,我发布代码是为了好玩,看看是否还有其他人来想出另一种解决方案,并且因为某个地方的某个人可能会看到它并且它可能会帮助他们解决类似的问题。免责声明;我不会在生产代码中使用它,它纯粹是为了我自己的享受而编写的。

void Main()
{
    string p = "PASS";
    var c = GetEnumNameByString<DocumentType>(p, typeof(DocumentExtendedType));
}

public enum DocumentType{ IdCard=0, Passport, DriversLicense }
public enum DocumentExtendedType { ID = 0, PASS, DRIVERS, NONE }

public TEnum GetEnumNameByString<TEnum>(string name, Type type)
{
    int index = Enum.Parse(type, name).GetHashCode();
    if(Enum.IsDefined(typeof(TEnum), index))
    {
        return (TEnum)Enum.GetValues(type).GetValue(index);
    }
    else
    {
        throw new IndexOutOfRangeException();
    }
}

我确实相信 switch case 更快,因为它不使用反射,尽管这应该适用于任何两个枚举,只要枚举在成员值方面具有相同的结构。这只是解决枚举无法继承问题的HACK。