Ошибка в C# 8.0 компиляторе или. NET Core 3 во время выполнения? - PullRequest
0 голосов
/ 30 марта 2020

Я думаю, что, возможно, обнаружил проблему либо с компилятором C# 8.0, либо с NET средой выполнения ядра относительно реализаций элементов интерфейса по умолчанию и общих параметров типа c.

Общая суть в том, что я реализовал очень простой дизайн, который можно использовать для воспроизведения исключения VerificiationException во время выполнения, которое я получаю при запуске фрагмента кода, который прекрасно компилируется и на самом деле должно быть отлично.

Итак, давайте перейдем к коду. Я создал пустое решение с двумя проектами: один C# библиотека с таргетингом .NETStandard 2.1 и один C# тестовый проект с таргетингом . NET Core 3.1 , где тест-проект ссылается на библиотеку.

Затем в проект библиотеки я добавил следующий код:

// In library project
namespace SomeLibrary
{
    public interface IMessageHandler<TMessage> { }

    public interface ISomeInterface<TMessage>
    {
        void DoSomething<TMessageHandler>() where TMessageHandler : class, IMessageHandler<TMessage> =>
            DoSomething<TMessageHandler>("Something");

        void DoSomething<TMessageHandler>(string value) where TMessageHandler : class, IMessageHandler<TMessage>;
    }

    public sealed class SomeClass<TMessage> : ISomeInterface<TMessage>
    {
        public void DoSomething<TMessageHandler>(string value) where TMessageHandler : class, IMessageHandler<TMessage> { }
    }
}

Обратите внимание, как DoSomething<TMessageHandler> -методы объявляют ограничение типа c на TMessageHandler он также ссылается на параметр типа generi c интерфейса TMessage.

. В тестовом проекте я добавил реализацию-заглушку интерфейса IMessageHandler<TMessage> (SomeHandler), чтобы иметь некоторый тип, удовлетворяющий ограничение параметра типа c. Затем я реализовал следующий простой тест, который вызывает перегрузку ISomeInterface<object>.DoSomething<SomeHandler> с реализацией по умолчанию (примечание: я использую MS Test ):

// In test-project.
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace SomeLibrary.Tests
{
    [TestClass]
    public sealed class SomeClassTest
    {
        [TestMethod]
        public void DoSomething_DoesSomething()
        {
            CreateSomeClass<object>().DoSomething<SomeHandler>();
        }

        private static ISomeInterface<TMessage> CreateSomeClass<TMessage>() =>
            new SomeClass<TMessage>();
    }

    public sealed class SomeHandler : IMessageHandler<object> { }
}

Как и следовало ожидать, все это прекрасно компилируется.

Однако, когда вы запускаете этот тест, CLR выбрасывает VerificationException в момент вызова DoSomething<...> -метода:

System. Security.VerificationException: метод ISomeInterface`1 [System.Object] .DoSomething: тип аргумента 'TMessageHandler' нарушает ограничение параметра типа 'TMessageHandler'.

VerificationException

Как будто среда выполнения не может видеть, что класс SomeHandler на самом деле удовлетворяет этому ограничению - что уже проверено компилятором.

После экспериментов, Я заметил, что проблема исчезнет, ​​если я изменю ограничение параметра типа на то, что не зависит от / использует параметр типа интерфейса TMessage. Например, если я просто опущу требование, что TMessageHandler реализует IMessageHandler<TMessage>, код работает просто отлично:

public interface ISomeInterface<TMessage>
{
    void DoSomething<TMessageHandler>() where TMessageHandler : class =>
        DoSomething<TMessageHandler>("Something");

    void DoSomething<TMessageHandler>(string value) where TMessageHandler : class;
}

Также возможно добавить другие ограничения, если они не используются TMessage.

Также обратите внимание, что если я сохраню ограничение параметра типа generi c в неизменном виде, но перенесу реализацию метода в SomeClass<TMessage> - это то, что вы сделали бы до C# 8.0 - тогда код также работает нормально, поэтому именно эта комбинация ограничений и реализации метода интерфейса по умолчанию делает систему взломанной.

Это ошибка в компиляторе или CLR, или я пропускаю важный шаг в моем мыслительном процессе?

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

Эта проблема была недавно решена в . net 5.0

1 голос
/ 01 апреля 2020

Я считаю, что это дубликат ошибки, первоначально сообщенной для Roslyn , которая затем была исправлена ​​как ошибка в CLR .

Похоже, это еще не исправлено, но имеет веху, которую нужно исправить. NET 5.0.

...