在尝试覆盖 ICollection<T>.IsReadOnly 的显式接口(interface)实现时来自 Collection<T> 的属性(property)类,我遇到了一些文档,指出显式接口(interface)成员实现不能被覆盖,因为它们不能有诸如 virtual 之类的修饰符。或 abstract .在 MSDN他们甚至指定如何通过创建另一个由显式接口(interface)成员实现调用的抽象或虚拟成员来使显式接口(interface)成员实现可用于继承。到目前为止没有问题。
但后来我想知道:为什么在 C# 中可以通过显式指定接口(interface)来覆盖任何显式实现的接口(interface)成员?
例如,假设我有一个像这样的简单接口(interface),带有一个属性和方法:
public interface IMyInterface
{
bool AlwaysFalse { get; }
bool IsTrue(bool value);
}
还有一个类A它明确地实现了接口(interface),并且有一个方法 Test()它调用自己的接口(interface)成员实现。
public class A : IMyInterface
{
bool IMyInterface.AlwaysFalse
{ get { return false; } }
bool IMyInterface.IsTrue(bool value)
{ return value; }
public bool Test()
{ return ((IMyInterface)this).AlwaysFalse; }
}
如您所见,这四个成员都不是虚拟的或抽象的,所以当我定义一个类时 B像这样:
public class B : A
{
public bool AlwaysFalse
{ get { return true; } }
public bool IsTrue(bool value)
{ return !value; }
}
那么你会期待一个 B 的实例转换为 A表现得像A .它确实:
A a = new A();
Console.WriteLine(((IMyInterface)a).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)a).IsTrue(false)); // False
Console.WriteLine(a.Test()); // False
A b = new B();
Console.WriteLine(((IMyInterface)b).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)b).IsTrue(false)); // False
Console.WriteLine(b.Test()); // False
现在来了。创建类 C这是 B 的精确副本除了类声明中的一件事:
public class C : A, IMyInterface
{ /* ... same as B ... */ }
现在是 C 的一个实例, 当转换到 A , 不像 A但喜欢C :
A c = new C();
Console.WriteLine(((IMyInterface)c).AlwaysFalse); // True
Console.WriteLine(((IMyInterface)c).IsTrue(false)); // True
Console.WriteLine(c.Test()); // True
即使是 Test()方法现在调用 C 中的覆盖方法!这是为什么?
最佳答案
这与显式接口(interface)实现无关;这只是继承和接口(interface)映射的一般规则的结果:如果类型 A 提供了 的隐式而不是显式实现,您将看到完全相同的结果>IMyInterface.
B 继承自类型A。没有任何内容被覆盖。B 提供自己的 AlwaysFalse 和 IsTrue 成员,但它们不实现 IMyInterface ; IMyInterface 的实现由继承自 A 的成员提供:当类型 B 的实例被转换为 IMyInterface 然后它的行为方式与类型 A 的实例完全相同,因为 A 提供实现接口(interface)的成员。C 继承自类型A。同样,没有任何内容被覆盖。C 提供了它自己的 AlwaysFalse 和 IsTrue 成员,但这次这些成员确实实现了 IMyInterface:当 C 类型的实例被转换为 IMyInterface 时,C 的成员提供接口(interface)实现,而不是 A 的成员。因为类型 A 显式实现了 IMyInterface 编译器不会警告 B 和 C 的成员正在隐藏 A 的成员;实际上,由于显式接口(interface)实现,A 的那些成员已经被隐藏。
如果您更改类型 A 以隐式而不是显式实现 IMyInterface,那么编译器会警告 B 和 的成员C 隐藏而不是覆盖 A 的成员,理想情况下您应该使用 new在 B 和 C 中声明这些成员时使用修饰符。
以下是语言规范中的一些相关内容。 (ECMA-334 spec 中的第 20.4.2 和 20.4.4 节;Microsoft C#4 spec 中的第 13.4.4 和 13.4.6 节。)
20.4.2 Interface mapping
The implementation of a particular interface member
I.M, whereIis the interface in which the memberMis declared, is determined by examining each class or structS, starting withCand repeating for each successive base class ofC, until a match is located.20.4.4 Interface re-implementation
A class that inherits an interface implementation is permitted to re-implement the interface by including it in the base class list. A re-implementation of an interface follows exactly the same interface mapping rules as an initial implementation of an interface. Thus, the inherited interface mapping has no effect whatsoever on the interface mapping established for the re-implementation of the interface.
关于C#:通过显式指定接口(interface)来覆盖属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3705308/
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m