【问题标题】:C# Reading Dictionary<String, List<String>> using LINQ or foreach loopC# 使用 LINQ 或 foreach 循环读取 Dictionary<String, List<String>>
【发布时间】:2015-05-28 22:54:30
【问题描述】:

我有一个字典对象如下:

private Dictionary<String, List<String>> errors =
        new Dictionary<string, List<string>>();

我已经在我的类 Product 中实现了 IDataErrorInfo。其中存储了验证属性(Id,Name)的错误。如果我们将字典视为结构,那么 TKey 将是字符串,它将包含 PropertyName 和 TValue 列表该属性的错误。这是一个代码:

public class Product : IDataErrorInfo
{
    private int idValue;

    public int Id
    {
        get { return idValue; }
        set { if (IsIdValid(value) && idValue != value) idValue = value; }
    }

    private string nameValue;
    public string Name
    {
        get { return nameValue; }
        set { if (IsNameValid(value) && nameValue != value) nameValue = value; }
    }


    {
        bool isValid = true;

        if (value < 5)
        {
            AddError("Id", ID_ERROR, false);
            isValid = false;
        }
        else RemoveError("Id", ID_ERROR);

        if (value < 10) AddError("Id", ID_WARNING, true);
        else RemoveError("Id", ID_WARNING);

        return isValid;
    }


    public bool IsNameValid(string value)
    {
        bool isValid = true;

        if (value.Contains(" "))
        {
            AddError("Name", NAME_ERROR, false);
            isValid = false;
        }
        else RemoveError("Name", NAME_ERROR);

        if (value.Length > 5) AddError("Name", NAME_WARNING, true);
        else RemoveError("Name", NAME_WARNING);

        return isValid;
    }

    private Dictionary<String, List<String>> errors =
        new Dictionary<string, List<string>>();
    private const string ID_ERROR = "Value cannot be less than 5.";
    private const string ID_WARNING = "Value should not be less than 10.";
    private const string NAME_ERROR = "Value must not contain any spaces.";
    private const string NAME_WARNING = "Value should be 5 characters or less.";


    public void AddError(string propertyName, string error, bool isWarning)
    {
        if (!errors.ContainsKey(propertyName))
            errors[propertyName] = new List<string>();

        if (!errors[propertyName].Contains(error))
        {
            if (isWarning) errors[propertyName].Add(error);
            else errors[propertyName].Insert(0, error);
        }
    }


    public void RemoveError(string propertyName, string error)
    {
        if (errors.ContainsKey(propertyName) &&
            errors[propertyName].Contains(error))
        {
            errors[propertyName].Remove(error);
            if (errors[propertyName].Count == 0) errors.Remove(propertyName);
        }
    }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string propertyName]
    {
        get
        {
            return (!errors.ContainsKey(propertyName) ? null :
                String.Join(Environment.NewLine, errors[propertyName]));
        }
    }
}

我想在我的类中创建方法,在该方法中我将使用 foreach 循环甚至更好的 LINQ 从 Dictionary 中读取所有内容。我该怎么做?

我的想法,不正确

public void ReadAllErrors()
    {


        StringBuilder sb = new StringBuilder();
        foreach (string propertyName in errors.Keys)
        {
            sb.AppendLine(propertyName + "\t");
            foreach (List<string> list in errors.Values)
            {
                foreach (string error in list)
                {
                    sb.AppendLine(error.ToString() + "\n");
                }

            }
        }
        MessageBox.Show(sb.ToString());
    }

谢谢!

【问题讨论】:

  • 您要遍历与 propertyName 关联的字符串列表,而不是每个键的所有值
  • 我想要这样的输出:ID 值不能小于 5。名称值应该是 5 个字符或更少。
  • 哦,你知道吗? ...好吧,请忽略我下面的解决方案!
  • 至少三个人认为您可能循环错误!大声笑...也许您应该查看以下三个几乎相同的解决方案之一,并确保您实际上并不想要更像他们返回的东西。

标签: c# linq dictionary


【解决方案1】:

我首先要说的是,这个Product : IDataErrorInfo 并没有让我觉得它是完成我认为你正在努力完成的事情的最优雅的架构。如果有的话,应该将与错误相关的方法和字段移到基类(而不是接口)中,否则您最终将在每个单独的类中重复所有这些逻辑。

但要回答您的直接问题,您可以按如下方式修复您的 ReadAllErrors() 函数:

public void ReadAllErrors()
{
    StringBuilder sb = new StringBuilder();
    foreach (string propertyName in errors.Keys)
    {
        sb.AppendLine(propertyName + "\t");
        foreach (string error in errors[propertyName])
        {
            sb.AppendLine(error.ToString() + "\n");
        }
    }
    MessageBox.Show(sb.ToString());
}

您可以像这样使用 LINQ 创建类似的东西:

MessageBox.Show(string.Join("\n", 
    errors.SelectMany(v => v.Value.Select(s => s)).ToArray()));

【讨论】:

    【解决方案2】:

    我面前没有编译器,但我认为你只是一个小逻辑错误,试试这个:

    public void ReadAllErrors()
    {
    
    
        StringBuilder sb = new StringBuilder();
        foreach (string propertyName in errors.Keys)
        {
          sb.AppendLine(propertyName + "\t");
          foreach (string error in errors[propertyName])
          {
            sb.AppendLine(error.ToString() + "\n");
          }
        }
        MessageBox.Show(sb.ToString());
    }
    

    【讨论】:

      【解决方案3】:

      IIUC 看起来您正在错误地迭代列表。这行得通吗?:

        StringBuilder sb = new StringBuilder();
        foreach (string propertyName in errors.Keys)
        {
          sb.AppendLine(propertyName + "\t");
            foreach (string error in errors[propertyName])
            {
              sb.AppendLine(error);
            }
        }
      

      如果不能,你能解释一下你得到的结果是什么吗?

      编辑: 一个 linq 查询可能类似于:

      MessageBox.Show(errors.Select(e => e.Key + "\r\n" + e.Value.Select(v => v + "\r\n")))
      

      我会说原版更具可读性。

      你可能会在某处注入 SB ...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-30
        • 2019-11-27
        • 1970-01-01
        相关资源
        最近更新 更多