Первый ярлык на быстрых истинах и ложных значениях:
if(ReferenceEqual(actual, expected))
return true;
if(actual == null || expected == null || actual.Count != expected.Count)
return false;
Это также обрабатывает проверку на нуль, поэтому все остальное, что мы делаем, не может вызвать исключение нулевой ссылки.Вы можете пропустить всю эту полосу, сравнивая количество, если оно у вас есть сразу после создания, как в вашем примере, но следует сохранить его, если вы поместите это в отдельный метод, на всякий случай.
Мы можем 'просто вызовите SequenceEqual в двух словарях, потому что мы не можем вернуть ключи в том же порядке.С другими типами для значения мы могли бы сделать:
return actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key));
Но это не сработает, потому что два равных по последовательности значения List<string>
не будут считаться равными методу DefaultEqualityComparer<List<string>>.Equals()
, который будетпозвоните в.
Мы могли бы создать IEqualityComparer<KeyValuePair<string, List<string>>>
, если бы мы были одержимы использованием SequenceEqual, но, вероятно, проще сделать подход без использования Linq, даже если Linq обычно проще и более лаконичен (если вынайти способ сделать это. Следовательно:
List<string> expectedVal;
foreach(KeyValuePair<string, List<string> kvp in actual)
{
if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal))
return false;
}
return true;
Варианты могут иметь дело с различными представлениями о равенстве. Например, мы можем использовать kvp.Value.OrderBy(x => x).SequenceEquals(expectedVal.OrderBy(x => x))
, если мы хотим рассмотреть два списка одинаковых предметов в разных порядкахкак равный.
В итоге, все вместе:
if(ReferenceEqual(actual, expected))
return true;
if(actual == null || expected == null || actual.Count != expected.Count)
return false;
List<string> expectedVal;
foreach(KeyValuePair<string, List<string> kvp in actual)
{
if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal))
return false;
}
return true;
Редактировать: просто для удовольствия, способ, который использует SequenceEquals:
internal class KvpSLSEq : IEqualityComparer<KeyValuePair<string, List<string>>>
{
public bool Equals(KeyValuePair<string, List<string>> x, KeyValuePair<string, List<string>> y)
{
return x.Key == y.Key && x.Value.Count == y.Value.Count && x.Value.SequenceEquals(y.Value);
}
public int GetHashCode(KeyValuePair<string, List<string>> obj)
{
//you could just throw NotImplementedException unless you'll reuse this elsewhere.
int hash = obj.Key.GetHashCode;
foreach(string val in obj.Value)
hash = hash * 31 + (val == null ? 0 : val.GetHashCode());
}
}
Это сделано, мы можемиспользуйте краткое:
actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key), new KvpSLSEq());
Но это действительно очень краткое, если KvpSLSEq будет использоваться и в других местах.