c# - FluentAssertions Should().BeEquivalentTo 不比较 EF 动态代理上的运行时派生类型

标签 c# entity-framework dynamic-proxy fluent-assertions

我正在使用 FluentAssertions 比较两个使用 Should().BeEquivalentTo() 的对象,其中一个对象是 EF 动态代理。但是,似乎 5.0.0 中 ShouldBeEquivalentToShouldAllBeEquivalentTo ( #593 ) 的统一在使用 RespectingRuntimeTypes 时破坏了功能。除非我为对象图中的每个类型显式添加 ComparingByMembers,否则不再比较已声明类型的派生类型的属性成员。使用其他设置有什么办法解决这个问题吗?

最佳答案

我已经编写了以下扩展方法来尝试解决该问题,但仅在运行时在动态代理上修复派生类型的问题似乎很麻烦:

public static class FluentAssertionsExtensions
{
    /// <summary>
    /// Extends the functionality of <see cref="EquivalencyAssertionOptions{TExpectation}" />.ComparingByMembers by recursing into the entire object graph
    /// of the T or passed object and marks all property reference types as types that should be compared by its members even though it may override the
    /// System.Object.Equals(System.Object) method. T should be used in conjunction with RespectingDeclaredTypes. The passed object should be used in
    /// conjunction with RespectingRuntimeTypes.
    /// </summary>
    public static EquivalencyAssertionOptions<T> ComparingByMembersRecursive<T>(this EquivalencyAssertionOptions<T> options, object obj = null)
    {
        var handledTypes = new HashSet<Type>();
        var items = new Stack<(object obj, Type type)>(new[] { (obj, obj?.GetType() ?? typeof(T)) });

        while (items.Any())
        {
            (object obj, Type type) item = items.Pop();
            Type type = item.obj?.GetType() ?? item.type;

            if (!handledTypes.Contains(type))
            {
                handledTypes.Add(type);

                foreach (PropertyInfo pi in type.GetProperties())
                {
                    object nextObject = item.obj != null ? pi.GetValue(item.obj) : null;
                    Type nextType = nextObject?.GetType() ?? pi.PropertyType;

                    // Skip string as it is essentially an array of chars, and needn't be processed.
                    if (nextType != typeof(string))
                    {
                        if (nextType.GetInterface(nameof(IEnumerable)) != null)
                        {
                            nextType = nextType.HasElementType ? nextType.GetElementType() : nextType.GetGenericArguments().First();

                            if (nextObject != null)
                            {
                                // Look at all objects in a collection in case any derive from the collection element type.
                                foreach (object enumObj in (IEnumerable)nextObject)
                                {
                                    items.Push((enumObj, nextType));
                                }

                                continue;
                            }
                        }

                        items.Push((nextObject, nextType));
                    }
                }

                if (type.IsClass && type != typeof(string))
                {
                    // ReSharper disable once PossibleNullReferenceException
                    options = (EquivalencyAssertionOptions<T>)options
                        .GetType()
                        .GetMethod(nameof(EquivalencyAssertionOptions<T>.ComparingByMembers))
                        .MakeGenericMethod(type).Invoke(options, null);
                }
            }
        }

        return options;
    }
}

应该这样称呼:

foo.Should().BeEquivalentTo(bar, o => o
    .RespectingRuntimeTypes()
    .ComparingByMembersRecursive(foo)
    .ExcludingMissingMembers());

关于c# - FluentAssertions Should().BeEquivalentTo 不比较 EF 动态代理上的运行时派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49327679/

相关文章:

c# - 无法在 Docker for Windows : "System cannot find the file specified" 中运行容器

java - 在运行时增强 java 对象

c# - 在标准 ASP.NET MVC 安装模板中模拟用户

c# - 在 C# (web api) 中测试经过身份验证的方法(使用不记名 token )的正确方法

entity-framework - Entity Framework Code First 的 SQL Server Express 连接字符串

c# - 从平面文件加载数据的通用实体

java - 什么是动态代理类,我为什么要使用一个?

c# - 基于反射的注入(inject)与动态代理 : Practical considerations?

c# - Visual Studio 自动生成的文件开头的那些字符是什么?

c# - 从以 id 作为外键的表中加载对象