C# 如何在FluentAssertions中使用Excluding来排除字典中的特定键值对

C# 如何在FluentAssertions中使用Excluding来排除字典中的特定键值对,c#,dictionary,fluent-assertions,C#,Dictionary,Fluent Assertions,我正在使用FluentAssertions与shouldbeeeequivalentto来比较两个类型为Dictionary的字典,但希望排除一个或多个特定的键值对(因为在本例中它们包含时间戳)。如何做到这一点 我尝试了如下操作:opt=>opt.Excluding(x=>x.Single(kv=>kv.Key==“MySearchKey”)但这会导致错误,例如:Message:System.ArgumentException:Expression(kv.Key==“MySearchKey”)>

我正在使用FluentAssertions与
shouldbeeeequivalentto
来比较两个类型为
Dictionary
的字典,但希望排除一个或多个特定的键值对(因为在本例中它们包含时间戳)。如何做到这一点

我尝试了如下操作:
opt=>opt.Excluding(x=>x.Single(kv=>kv.Key==“MySearchKey”)
但这会导致错误,例如:
Message:System.ArgumentException:Expression(kv.Key==“MySearchKey”)>不能用于选择成员。

我想要的可能吗?或者我应该只排除值而不排除对(这可能更好,因为将检查密钥的存在性)?谢谢

Excluding()
用于排除类型的成员,而不是排除集合的成员,有关详细信息,请参阅

注意:下面的代码是针对Fluent断言的当前稳定版本4.19.4的

例如: 您希望比较
Person
PersonDTO
的实例,但
Person
包含要从对象比较中排除的
另一个属性

var person = new Person
{
    FirstName = "John",
    LastName = "McClane",
    AnotherProperty = 42
};

var personDTO = new PersonDTO
{
    FirstName = "John",
    LastName = "McClane"
};
在这里,您可以使用
Exclude
排除类型的成员

person.ShouldBeEquivalentTo(personDTO, options => options.Excluding(e => e.AnotherProperty));
在您的具体案例中,我不会使用
应与
等效。
考虑这两个字典实例,在这里要省略一个集合的成员,这里的成员有“代码>键= =“未知”< /代码> .<
这将给出以下断言失败消息:

FluentAssertions.Execution.AssertionFailedException: 'Expected collection to be equal to {[one, 1], [two, 2], [three, 3]}, but {[one, 1], [two, 2], [three, 3], [fail, -2]} contains 1 item(s) too many.'
否则,请将过滤后的可枚举项返回到字典中:

Dictionary<string, int> filteredDict = actual.Where(e => e.Key != "unknown")
    .ToDictionary(e => e.Key, e => e.Value);
这将给出以下断言失败消息:

FluentAssertions.Execution.AssertionFailedException: 'Expected dictionary to be equal to {[one, 1], [two, 2], [three, 3]}, but found additional keys {"fail"}.'
如果您想使用第二种方法并且经常这样做,那么可以创建扩展方法来提取从测试方法中删除成员的逻辑

public static class DictionaryExtensions
{
    public static IDictionary<TKey, TValue> ExceptKeys<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TKey[] keys)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (keys == null) throw new ArgumentNullException(nameof(keys));

        return dictionary.Where(e => !keys.Contains(e.Key)).ToDictionary(e => e.Key, e => e.Value);
    }

    public static IDictionary<TKey, TValue> ExceptValues<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TValue[] values)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (values == null) throw new ArgumentNullException(nameof(values));

        return dictionary.Where(e => !values.Contains(e.Value)).ToDictionary(e => e.Key, e => e.Value);
    }
}
Excluding()
用于排除类型的成员,而不是排除集合的成员,有关详细信息,请参阅

注意:下面的代码是针对Fluent断言的当前稳定版本4.19.4的

例如: 您希望比较
Person
PersonDTO
的实例,但
Person
包含要从对象比较中排除的
另一个属性

var person = new Person
{
    FirstName = "John",
    LastName = "McClane",
    AnotherProperty = 42
};

var personDTO = new PersonDTO
{
    FirstName = "John",
    LastName = "McClane"
};
在这里,您可以使用
Exclude
排除类型的成员

person.ShouldBeEquivalentTo(personDTO, options => options.Excluding(e => e.AnotherProperty));
在您的具体案例中,我不会使用
应与
等效。
考虑这两个字典实例,在这里要省略一个集合的成员,这里的成员有“代码>键= =“未知”< /代码> .<
这将给出以下断言失败消息:

FluentAssertions.Execution.AssertionFailedException: 'Expected collection to be equal to {[one, 1], [two, 2], [three, 3]}, but {[one, 1], [two, 2], [three, 3], [fail, -2]} contains 1 item(s) too many.'
否则,请将过滤后的可枚举项返回到字典中:

Dictionary<string, int> filteredDict = actual.Where(e => e.Key != "unknown")
    .ToDictionary(e => e.Key, e => e.Value);
这将给出以下断言失败消息:

FluentAssertions.Execution.AssertionFailedException: 'Expected dictionary to be equal to {[one, 1], [two, 2], [three, 3]}, but found additional keys {"fail"}.'
如果您想使用第二种方法并且经常这样做,那么可以创建扩展方法来提取从测试方法中删除成员的逻辑

public static class DictionaryExtensions
{
    public static IDictionary<TKey, TValue> ExceptKeys<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TKey[] keys)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (keys == null) throw new ArgumentNullException(nameof(keys));

        return dictionary.Where(e => !keys.Contains(e.Key)).ToDictionary(e => e.Key, e => e.Value);
    }

    public static IDictionary<TKey, TValue> ExceptValues<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, params TValue[] values)
    {
        if (dictionary == null) throw new ArgumentNullException(nameof(dictionary));
        if (values == null) throw new ArgumentNullException(nameof(values));

        return dictionary.Where(e => !values.Contains(e.Value)).ToDictionary(e => e.Key, e => e.Value);
    }
}

为什么不使用linq exclude排除键值对,并比较results@Nkosi,感谢您的建议,我现在正在使用类似的筛选方法(如下面Jonas所建议的)。为什么不使用linq exclude排除键值对并比较results@Nkosi,谢谢你的建议,我正在使用类似的过滤方法(正如下面乔纳斯建议的那样)现在。乔纳斯,谢谢你非常透彻的解释!我习惯于应该是等价的,因为我大部分时间都在比较对象和对象。应该().Equal()在比较字典时确实更好。我还切换到了您的筛选解决方案。这是一种很好的方法,非常适合我的需要。再次感谢!请注意,使用ExceptKeys和ExceptValues时要小心,因为它们不会保留原始字典字典键的相等比较器。Jonas,感谢您的帮助透彻的解释!我习惯了应该是等价的,因为我大部分时间都在比较对象和对象。应该().Equal()在比较字典时确实要好得多。我还切换到了您的筛选解决方案。这是一种很好的方法,非常适合我的需要。再次感谢!请注意,使用ExceptKeys和ExceptValues时要小心,因为它们不会保留原始字典字典键的相等比较器。