C# 如何对文字字符串参数设置约束

C# 如何对文字字符串参数设置约束,c#,constraints,parameter-passing,C#,Constraints,Parameter Passing,我不得不说,标题太差,无法描述问题,但这是我唯一能想到的。无论如何,假设我得到了以下枚举: public enum DocumentType{ IdCard=0, Passport, DriversLicense } 我有一个接受字符串并返回上述枚举的方法: public DocumentType GetDocTypeByString(string docType){ switch (docType) { case "ID":

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

public enum DocumentType{
      IdCard=0,
      Passport,
      DriversLicense
}
我有一个接受字符串并返回上述枚举的方法:

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

现在,如果传递的字符串不满足任何开关条件,该怎么办?最愚蠢的事情是创建返回类型对象,但这是很少有人会做的事情。如果枚举是我的,我会添加一个名为“None”的附加值,如果不匹配,则返回该值,但我无法控制它。然后我想,是否有可能将输入限制为某些值。就C#而言,我几乎完全肯定这是不可能的,但我还是决定问。在这种情况下,你会推荐吗?

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

throw new ArgumentException("docType");
技术上甚至是

throw new ArgumentOutOfRangeException("docType");
这是正确的,但我从未见过在“数值”索引之外使用它

例如,如果使用非法值,
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;
}

您可以将返回类型设置为null,并执行如下操作:

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

这里有几件事你可以做,你选择哪一件取决于你期望这个方法的输入来自哪里。如果获取无效字符串表示程序员出错的情况,那么最好的方法是抛出异常

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

 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 string DocumentType GetDocTypeByString(string docType)
{
文档类型结果;
如果(!tryGetDoctTypeByString(out结果))抛出新的ArgumentException(“docType”);
返回结果;
}
public bool tryGetDoctTypeByString(字符串docType,out DocumentType结果)
{
//您可能应该将其存储为类的静态成员
var-mapping=newdictionary(){
{“ID”,DocumentType.IdCard}
...
};
返回mapping.TryGetValue(docType,out结果);
}

我会这样写:

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

您可以使用代码契约来指定所需的确切值。它比“if-throw”方法更简洁


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

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();
    }
}
void Main()
{
字符串p=“通过”;
var c=GetEnumNameByString(p,typeof(DocumentExtendedType));
}
公共枚举文档类型{IdCard=0,Passport,DriversLicense}
公共枚举DocumentExtendedType{ID=0,通过,驱动程序,无}
public TEnum GetEnumNameByString(字符串名称,类型)
{
int index=Enum.Parse(类型、名称).GetHashCode();
如果(枚举已定义(类型(十个),索引))
{
return(TEnum)Enum.GetValues(type).GetValue(index);
}
其他的
{
抛出新的IndexOutOfRangeException();
}
}

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

在这种情况下,您需要一些值,因此应该抛出异常。Null是许多错误的来源,最好避免这种情况。您从(ui?)获取字符串的地方。您不能使用枚举吗?我可能会通过不让用户输入来确保安全,但我只是好奇。如果情况是ID和IdCard具有相同的名称,而在这个特定的情况下它们没有相同的名称,那么这会起作用。嗯,为什么我不能想到out参数呢。“这是一个很好的例子。@MikeJM我只是在开始玩
Enum.Parse
以查看它抛出了什么异常时才注意到它。