Замок DynamicProxy - сбой при создании прокси-сервера с использованием GTP, используемого в качестве GTR

ОК, теперь я действительно смущен.

Я изначально имел эту проблему, которая, согласно плакатам, была связана с версией Castle.DynamicProxy, которая ILMerged в последнюю библиотеку Rhino.Mocks. Он, по мнению нескольких властей по этому вопросу, был зафиксирован в последнем замке, но эта библиотека не превратилась в новый Rhino.Mocks. Большинство людей говорят "просто скачайте источник Rhino и последний замок и создайте свою собственную версию".

Итак, я сделал именно это; Я схватил ZIP файл источника Rhino от Ayende GitHub, открыл его и построил. Затем, как хороший маленький TDDer, я создал unit test, чтобы убедиться, что мои изменения сработали (потому что последний Castle сбрасывает DynamicProxy в Core, требуя значительных изменений ссылок):

    [Test]
    public void MockOfInterfaceMethodWithInterfaceGTR()
    {
        var mock = mocks.DynamicMock<ITestRestrictedInterface>();
        Assert.NotNull(mock);
        Expect.Call(mock.TestMethod(new Object2())).IgnoreArguments().Return(5);
        mocks.ReplayAll();
        Assert.AreEqual(5, mock.TestMethod(new Object2()));
    }

...

internal interface ITestGenericInterface<TRest> where TRest:IObject1
{
    int TestMethod<T>(T input) where T : TRest;
}

internal interface ITestRestrictedInterface:ITestGenericInterface<IObject2> { }

internal interface IObject1 { }
internal interface IObject2:IObject1 { }

internal class Object2:IObject2 { } 

Результат, когда вы запускаете мой собственный код производства с последним выпущенным Rhino? Ошибка со следующим сообщением:

System.TypeLoadException: метод TestMethod по типу 'ITestRestrictedInterfaceProxy83ad369cdf41472c857f61561d434436' от сборка 'DynamicProxyGenAssembly2, Версия = 0.0.0.0, Культура = нейтральная, PublicKeyToken = null 'попытался неявно реализовать метод интерфейса с более слабыми параметрами параметра.

... Однако, когда я копирую и вставляю этот тест в инструмент в проекте Rhino.Mocks.Tests, без внесения каких-либо изменений в библиотеки ссылок, тестовый PASSES. Я сделал нулевые изменения для загруженного источника. Я внес изменения ZERO в метод тестирования и связанные с ним интерфейсы/объекты с обеих сторон. Я построил новую библиотеку Rhino.Mocks DLL (без IL-слияния Castle libs) и скопировал ее с помощью Castle libs обратно в мое производственное решение, перезапустил тест и все еще не смог с тем же сообщением.

WTF?

Ответ 1

Я не эксперт по замкам и гуру компилятора, но я считаю, что проблема в том, что проблема заключается в магии, скрытой внутри сборки RhinoMocks.Sests:

Из https://github.com/ayende/rhino-mocks/blob/master/Rhino.Mocks.Tests/TestInfo.cs

using System.Runtime.CompilerServices;
using Rhino.Mocks;

[assembly: InternalsVisibleTo(RhinoMocks.StrongName)]

И для полноты радиуса RhinoMocks.StrongName определяется как:

/// <summary>
/// Used for [assembly: InternalsVisibleTo(RhinoMocks.StrongName)]
/// Used for [assembly: InternalsVisibleTo(RhinoMocks.NormalName)]
/// </summary>
public static class RhinoMocks
{
    /// <summary>
    /// Strong name for the Dynamic Proxy assemblies. Used for InternalsVisibleTo specification.
    /// </summary>
    public const string StrongName =
        "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7";

    /// <summary>
    /// Normal name for dynamic proxy assemblies. Used for InternalsVisibleTo specification.
    /// </summary>
    public const string NormalName = "DynamicProxyGenAssembly2";

    /// <summary>
    /// Logs all method calls for methods
    /// </summary>
    public static IExpectationLogger Logger = new NullLogger();
}

Я видел подобную проблему при использовании Moq, которая связана с этой проблемой.

Проблема заключается в том, что DynamicProxy в Castle необходимо динамически выводить новый тип, но не имеет видимости, чтобы увидеть ваш интерфейс, который является внутренним для вашей сборки. Простое добавление InternalsVisibleTo к DynamicProxyGenAssembly2 в тестовую библиотеку должно решить проблему.