Ошибка «невозможно реализовать элемент интерфейса», когда интерфейс и бетон находятся в разных проектах - PullRequest
47 голосов
/ 08 мая 2011

Компилируется:

public interface IMyInterface
{
    event Action<dynamic> OnSomeEvent;
}

class MyInterface : IMyInterface
{
    public event Action<dynamic> OnSomeEvent;
}

Но когда я разделяю интерфейс и реализацию для разных проектов, я получаю:

Accessor 'TestProject2.MyInterface.OnSomeEvent.remove'не удается реализовать элемент интерфейса InterfaceNamespace.IMyInterface.remove_OnSomeEvent (System.Action) для типа «TestProject2.MyInterface».Используйте явную реализацию интерфейса.

Это происходит только с динамическим параметром ...

Ответы [ 3 ]

30 голосов
/ 08 мая 2011

Хороший улов. Похоже, это возможно ошибка в компиляторе C # - я пингую Эрика Липперта, чтобы узнать, что он думает. (dynamic может быть немного хитрым; вполне может быть вполне веская, но неочевидная причина этой ошибки.)

РЕДАКТИРОВАТЬ: Код ниже появляется не , чтобы работать в конце концов. Я мог бы поклясться, что это работает сегодня утром ... Я очень смущен тем, что происходит , Согласно комментариям Саймона, код завершается ошибкой с сообщением о том, что он не поддерживается языком.

Обратите внимание, что если вы делаете , используете явную реализацию интерфейса, то, похоже, она прекрасно компилируется:

// Doesn't actually compile - see edit above
class MyInterface : IMyInterface
{
    private Action<dynamic> foo;

    event Action<dynamic> IMyInterface.OnSomeEvent
    {
        // TODO (potentially): thread safety
        add { foo += value; }
        remove { foo -= value; }
    }
}

РЕДАКТИРОВАТЬ: Остальная часть этого ответа остается в силе ...

Обратите внимание, что вы не можете указать событие в форме поля как явным образом реализованное событие, т. Е. Это не работает:

event Action<dynamic> IMyInterface.OnSomeEvent;

выдает следующее сообщение об ошибке:

Test.cs (15,39): ошибка CS0071: явная реализация интерфейса в событии должна использовать синтаксис доступа к событию

И если вы просто попытаетесь перейти на синтаксис метода доступа к событию, вы получите ту же ошибку, что и оригинальный код.

Обратите внимание, что изменение события на свойство прекрасно работает с автоматически реализуемой реализацией свойства.

9 голосов
/ 09 мая 2011

Спасибо за публикацию этого вопроса, и спасибо Джону за то, что отправили его мне.Я поместил это в очередь на расследование одного из наших тестеров, который специализируется на «динамике».Посмотрим, сможем ли мы выяснить, что здесь происходит.Это, безусловно, пахнет как ошибка.

В будущем рассмотрите возможность размещения подобных вещей на connect.microsoft.com;это ускоряет тестирование и дает нам лучший механизм для получения дополнительной информации о проблеме.

2 голосов
/ 09 мая 2011

Этот ответ должен высказать мои мысли об этой интересной проблеме.Не реальный ответ, но вклад во все обсуждение, который слишком мал для обычного комментария .

Я проверил несколько вещей, этот интерфейс:

namespace DifferentAssemblyNamespace
{
    public interface IBar
    {
        event Action<dynamic> OnSomeEvent;
    }
}

и его реализация:

// implicit interface implementation
// generates compile error "Explicit interface implementation"
public class Foo1 : IBar
{
    private Action<dynamic> foo;
    public event Action<dynamic> OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

// implicit interface implementation
// generates compile error "Not supported by the language"
public class Foo2 : IBar
{
    private Action<dynamic> foo;

    event Action<dynamic> IBar.OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

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

, но .. если мы вызываем дженерики для справки и используем параметр типа вместо использования dynamic, например:

namespace DifferentAssemblyNamespace
{
    public interface IGenericBar<T>
    {
        event Action<T> OnSomeEvent;
    }
}

и его реализация.

// implicit interface implementation
public class Foo3<T> : IGenericBar<T>
{
    private Action<T> foo;

    event Action<T> IGenericBar<T>.OnSomeEvent
    {
        add { foo += value; }
        remove { foo -= value; }
    }
}

дляпо какой-то причине мы можем построить (как следует) и запустить:

/** does build **/
IGenericBar<dynamic> f = new Foo3<dynamic>();
f.OnSomeEvent += new Action<dynamic>(f_OnSomeEvent);

кажется, что параметр типа делает что-то дополнительное , что компилятор доволен.

IЯ не уверен, что происходит, поэтому я хотел бы также знать.

предположение, очень гипотетическое (возможно, дерьмо)

но в настоящее время я ставлюмои два цента при сравнении типов должны быть сделаны через методы добавления / удаления в связанном списке, который содержит target / meсобытия.

Могу поспорить, что компилятор решает проблему, заключающуюся в том, что он не может гарантировать, какая динамика находится во внешней сборке, и поэтому не может определить, есть ли элемент в списке или нет, что необходимо для добавления или удаления их.(Отсюда явная реализация интерфейса)

Мы все знаем, что это всего лишь некоторый атрибутный объект, но все же кажется, что ему нужен дополнительный шаг, когда гарантируется некоторый строгий тип, и именно это делает T при компиляции.время.

/ предположение, весьма гипотетическое (возможно, дерьмо)

...