【问题标题】:How could I put a constraint on a literal string parameter如何对文字字符串参数施加约束
【发布时间】:2015-05-08 06:50:25
【问题描述】:

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

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# 而言,我几乎完全确定这是不可能的,但我还是决定问一下。在这种情况下你会推荐吗?

【问题讨论】:

  • 您从哪里获取字符串(用户界面?)。你能不让这个使用枚举吗?
  • 我可能会通过不让用户输入来确保它的安全,但我只是好奇。

标签: c# constraints parameter-passing


【解决方案1】:

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

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;
}

【讨论】:

  • Hmmmm,为什么我想不出out参数。这是一个很好的。
  • @MikeJM 我只有在开始使用Enum.Parse 以查看它抛出了什么异常时才注意到它。
【解决方案2】:

你可以让返回类型为空,然后这样做:

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

【讨论】:

  • 在这种情况下,您期望一些值,因此您应该抛出异常。 Null 是许多错误的根源,最好避免这种情况。
【解决方案3】:

您可以使用代码协定来指定您期望的确切值。它比“if throw”方法干净一点。

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

【讨论】:

    【解决方案4】:

    我会这样写:

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

    【讨论】:

    【解决方案5】:

    您可以在此处执行几项操作,您选择哪一项取决于您期望此方法的输入来自何处。如果获取无效字符串代表程序员出错的情况,那么最好的办法就是抛出异常。

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

     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);
    }
    

    【讨论】:

      【解决方案6】:

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

      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。

      【讨论】:

        猜你喜欢
        • 2015-11-26
        • 1970-01-01
        • 2023-03-27
        • 2016-01-15
        • 2021-03-21
        • 1970-01-01
        • 2017-11-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多