c# - 为什么一个属性被认为是不明确的,而另一个接口(interface)是只设置的?

标签 c# compiler-errors

在以下代码中:

interface IGet { int Value { get; } }

interface ISet { int Value { set; } }

interface IBoth : IGet, ISet { }

class Test
{
    public void Bla(IBoth a)
    {
        var x = a.Value; // Error: Ambiguity between 'IGet.Value' and 'ISet.Value'
    }
}

我收到一个错误:

Ambiguity between 'IGet.Value' and 'ISet.Value'



为什么编译器不能确定访问的属性必须来自IGet ?

编辑 - 我猜编译器首先尝试确定正在访问哪个属性,然后才检查它是 get 还是 set。问题是——为什么?为什么不排除那些不提供 setter/getter 的候选人?为什么不解决实际的 get/set 方法并忽略它是一个属性的事实?

更新 :Some more code using methods instead of properties ,问题不存在的地方。属性并不完全像一对方法。

最佳答案

I'm guessing the compiler first tries to determine which property is being accessed, and only then checks whether it's a get or a set.


你的猜测是正确的。

The question is - why? Why not rule out those candidates that don't provide a getter? Why not resolve the actual get/set methods and ignore the fact it's a property?

The compiler could resolve all property candidates and then rule out the ones that don't provide get - why doesn't it do that? – sinelaw

Because the language designers didn't design it that way? – Robert Harvey

@sinelaw Because that's not how the C# language is defined. It isn't that it couldn't be done, it is simply that it's not done. – user2864740

I'm sure they designed it that way (unlikely they overlooked this situation) - but what's the reasoning? – sinelaw

@sinelaw Presumably because they didn't feel the benefit from such a feature would out way the added complexity in developing it. – p.s.w.g


pswg 在这里走在正确的轨道上,但我们可以更具体。
这里的基本设计原则是 分析从内到外 不考虑“上下文线索”。当表达式的含义取决于其直接上下文时,这对读者来说既令人困惑,又对编译器和 IDE 开发人员来说很困难。我们要做的是明确地找出每个表达式的含义,然后验证它在其上下文中是否有效。我们不想反其道而行之,然后说“好吧,这个表达有歧义,所以让我使用上下文作为线索”。
更具体地说:首先编译器必须确定 a 的含义,然后是 a.Value ,然后确定赋值是否合法。编译器没有说“好吧,我无法弄清楚 a.Value 的两个属性中的哪一个,因为它不明确,但我将通过假装我已经弄清楚了,然后回去修补问题我意识到我处于一项任务的值(value)方面,而其中只有一项具有值(value)”。编译器也不会说“当我在作业的左侧时我将使用一种查找算法,而当我在右侧时将使用不同的查找算法”。
(旁白:当然,从技术上讲,我们在这里不是在赋值;我们是在隐式类型本地的初始化程序中,它不被归类为赋值运算符的用法。但它在逻辑上等同于这样,所以我们将让它过去而不做进一步评论。)
这个一般规则有一些异常(exception),它们针对特定的常见情况。例如,编译器确实知道在 a.B() 形式的表达式中,B 需要是可调用的;成员查找算法会自动拒绝不可调用的成员而不会出错。 Lambdas 当然完全拒绝这个原则; lambda 的含义完全由其上下文决定。完成这项工作需要大量的工作——这是我为 C# 3 提供的功能之一——我们进行了大量投资以确保算法在常见场景中的性能。任何时候你从外到内,从内到外同时推理,你最终会陷入潜在的指数情况,在这种情况下,你必须进行所有可能的试验绑定(bind),然后选择唯一有效的绑定(bind)。对于像类型推断的 lambdas 这样的强大功能来说,这个成本是值得的。使其他形式的上下文敏感性工作,特别是对于您描述的模糊场景,不是花费有限预算的好方法。

So the code example in my answer works because it "merges" the two property definitions into a single call (eliminating the compiler ambiguity) while fulfilling the two interface contracts for both the getter and the setter? Robert Harvey


澄清一下,罗伯特从他删除的答案中得到的代码是:
public class GetSet : ISet, IGet
{
    public string Value { get; set; }
}
...
getSet.Value = "This is a test";
Debug.Print(getSet.Value); //Prints "This is a test"
罗伯特 我不确定我是否理解你的问题。您的代码之所以有效,是因为首先满足了 ISetIGet 的契约(Contract)。 GetSet 类具有每个成员所需的所有成员和明确的映射。其次是因为您的调用站点根本不使用这些接口(interface);它只是直接调用类的成员。为什么它不起作用?
现在解决您删除的答案中的一点:

Just having another interface that inherits the original two isn't going to work, because there's no backing field to bind to.


不,这不是正确的分析。这与该属性是否实际实现为编译器生成的字段无关。请记住,接口(interface)上的属性只是定义 get_Valueset_Value 方法的奇特方式。只要实现类上存在具有所需方法的属性,就满足了接口(interface)要求。如何实现该属性取决于类。

one class property fulfills the Interface of two different contracts.


是的!那不是问题。只要可以明确确定从接口(interface)成员到类/结构成员的映射,就可以了。例如:
interface IFoo
{
    void M();
}

interface IBar
{
    void M();
}

class C : IFoo, IBar 
{ 
    public void M() { } 
}
M 可以作为 IFoo.MIBar.M 执行双重任务。
当无法轻松确定哪个方法与接口(interface)匹配时,就会遇到麻烦。有关详细信息,请参阅我关于该主题的文章:
http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx
对于一些有趣的相关恶作剧,请参阅这个问题和答案,我和 Lucian 都提到过:
Generic type parameter covariance and multiple interface implementations

关于c# - 为什么一个属性被认为是不明确的,而另一个接口(interface)是只设置的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20412783/

相关文章:

c++ - Boost文件系统编译错误

c# - WCF 服务中的操作筛选器

c# - 配置错误 : Unrecognized attribute 'maxBufferSize'

Java静态方法无法编译

perl - 如何在Perl中为简单的I/O子例程创建单元测试

c++ - 为什么编译器无法区分 typedef 和非 typedef?

c# - 链接按钮打开一个模态弹出窗口,但弹出窗口立即关闭

c# - 在单独的项目中共享 javascript 文件

c# - DateTime.ParseExact 具有可变的秒数

gwt - 使用跨站点支持编译 GWT 代码时出错