C# &引用;无法实现接口成员“;接口和混凝土在不同项目中时出错

C# &引用;无法实现接口成员“;接口和混凝土在不同项目中时出错,c#,events,dynamic,C#,Events,Dynamic,这包括: public interface IMyInterface { event Action<dynamic> OnSomeEvent; } class MyInterface : IMyInterface { public event Action<dynamic> OnSomeEvent; } 公共接口IMyInterface { 对某些事件的事件操作; } 类MyInterface:IMyInterface { 针对某些事件的公共事件行动;

这包括:

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

class MyInterface : IMyInterface
{
    public event Action<dynamic> OnSomeEvent;
}
公共接口IMyInterface
{
对某些事件的事件操作;
}
类MyInterface:IMyInterface
{
针对某些事件的公共事件行动;
}
但是,当我将接口和实现分离到不同的项目时,我得到:

存取器 'TestProject2.MyInterface.OnSomeEvent.remove' 无法实现接口成员 'InterfaceNamespace.IMyInterface.remove_OnSomeEvent(System.Action)' 对于类型“TestProject2.MyInterface”。 使用显式接口 实施

// 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; }
    }
}

这仅在动态参数下发生…

捕捉良好。这看起来可能是C#编译器中的一个bug——我会打电话给Eric Lippert看看他是怎么想的。(
dynamic
可能有点棘手;这个错误可能有一个非常好但不明显的原因。)

编辑:下面的代码似乎根本不起作用。我可以发誓我今天早上就让它起作用了。。。我对发生的事感到很困惑。根据Simon的评论,代码失败,并显示一条消息,表示该语言不支持该代码

请注意,如果确实使用显式接口实现,则它似乎可以正常编译:

// 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; }
    }
}
//实际上没有编译-请参见上面的编辑
类MyInterface:IMyInterface
{
私人行动基金;
事件操作IMyInterface.OnSomeEvent
{
//TODO(潜在):线程安全
添加{foo+=value;}
删除{foo-=value;}
}
}

编辑:这个答案的其余部分仍然有效

请注意,不能将类似字段的事件指定为显式实现的事件,即,这不起作用:

event Action<dynamic> IMyInterface.OnSomeEvent;
事件操作IMyInterface.OnSomeEvent;
它给出以下错误消息:

cs(15,39):错误CS0071:事件的显式接口实现必须使用事件访问器语法

如果您只是尝试更改事件访问器语法,则会得到与 原始代码


请注意,将事件更改为属性可以与自动实现的属性实现配合使用。

感谢您发布此问题,也感谢Jon向我发送此问题。我已经把它放在我们的一位测试人员的调查队列中,他专门研究“动态”。我们看看能不能弄清楚这里发生了什么。它闻起来真像虫子

// 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; }
    }
}

将来,考虑把这样的东西张贴到Calp.MyStftcom上;这让测试人员更快地了解它,并为我们提供了一个更好的机制来获取关于这个问题的更多信息。

这个答案是为了阐述我对这个有趣问题的想法。这不是一个真正的答案,而是对整个讨论的贡献,对于一个普通的评论来说,这个贡献太小了

我检查了一些东西,这个界面:

namespace DifferentAssemblyNamespace
{
    public interface IBar
    {
        event Action<dynamic> 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; }
    }
}
//隐式接口实现
公共类Foo3:IGenericBar
{
私人行动基金;
事件操作IGenericBar.OnSomeEvent
{
添加{foo+=value;}
删除{foo-=value;}
}
}
出于某种原因,我们可以构建(它应该)并运行:

/**确实可以构建**/
IGenericBar f=新的Foo3();
f、 OnSomeEvent+=新操作(f_OnSomeEvent);
类型参数似乎做了一些编译器满意的额外工作

我不知道发生了什么,所以我也想知道

假设,高度假设(可能是废话)

但是现在我把我的两分钱放在 类型的比较必须是 通过中的“添加/删除访问者”创建 保存链接的链接列表 事件的目标/方法

我敢打赌 编译器在 它不能保证什么的问题 dynamic位于外部程序集中,因此无法确定元素是否已在列表中,这是添加或删除它们所必需的。(因此显式接口实现)

我们都知道这只是一个小问题 属性化对象,但它仍然看起来 它需要一个额外的步骤 强类型是有保证的,这就是 T在编译时所做的事情


/假设,高度假设性(可能是废话)

我想知道编译器如何知道如何保护覆盖,然后在您分开编译项目时识别如何处理动态。是否有任何配置使显式接口实现工作?我收到一个
错误CS0682:“ConsoleApplication1.MyInterface.ClassLibrary1.IMyInterface.OnSomeEvent”无法实现“ClassLibrary1.IMyInterface.OnSomeEvent”,因为它不受试图编译的语言的支持。@Simon:您使用的是什么版本的C#编译器?动态是在C#4中引入的。@Caspar:对不起,我刚刚注意到你的评论。你能说得更详细些吗?请注意,类型为
Action的属性没有问题。
@Caspar:这里应该发生的“魔力”是在编译时将一个操作转换为Action。我们不会试图将其视为动作或动作或其他任何东西,这取决于分配给它的运行时类型。“dynamic”只是穿着华丽衣服的“object”。整个问题的有趣之处在于,如果你通过一个泛型T传递
dynamic
,它就会编译得很好。因此,public
interface-IMyInterface{event Action OnSomeEvent;}
及其正确的实现是一个
ns.IMyInterface=new class MyInterface()
编译,即使接口位于不同的程序集中。将
动态
包装在T中与直接使用它不同/更严格??见我的答案,我详细阐述了它。
/** does build **/
IGenericBar<dynamic> f = new Foo3<dynamic>();
f.OnSomeEvent += new Action<dynamic>(f_OnSomeEvent);