Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>An interface is a contract. It says "I can do these things." What's the point of someone handing you an instance of <code>IInterface</code> wherein you can't use some of the methods in that contract because they've been marked not public?</p> <p>This is the rationale for designing the language in this way. The specification for this is in §13.2 of the language specification:</p> <blockquote> <p>All interface members implicitly have public access. It is a compile-time error for interface member declarations to include any modifiers. In particular, interfaces members cannot be declared with the modifiers <code>abstract</code>, <code>public</code>, <code>protected</code>, <code>internal</code>, <code>private,</code> <code>virtual</code>, <code>override</code>, or <code>static</code>.</p> </blockquote> <p>As for your code, that is an example of <a href="http://msdn.microsoft.com/en-us/library/ms173157.aspx" rel="noreferrer">explicit interface implementation</a>. It is most useful for when a class or struct implements two interfaces each with a member having the same signature. For example, both <code>IEnumerable</code> and <code>IEnumerable&lt;T&gt;</code> define a method <code>GetEnumerator</code> accepting no parameters.</p> <pre><code>public interface IEnumerable { IEnumerator GetEnumerator(); } public interface IEnumerable&lt;T&gt; : IEnumerable { IEnumerator&lt;T&gt; GetEnumerator(); } </code></pre> <p>Note that by the above definitions, any class that implements <code>IEnumerable&lt;T&gt;</code> must also implement <code>IEnumerable</code>. Keep in mind that the return type is not part of the signature and thus we have a conflict with <code>IEnumerable.GetEnumerator</code> and <code>IEnumerable&lt;T&gt;.GetEnumerator</code>. This is what explicit interface implementation is meant to solve:</p> <pre><code>class X&lt;T&gt; : IEnumerable&lt;T&gt; { List&lt;T&gt; _list = new List&lt;T&gt;(); public IEnumerator&lt;T&gt; GetEnumerator() { return _list.GetEnumerator(); } IEnumerator GetEnumerator() { return GetEnumerator(); // invokes IEnumerable&lt;T&gt;.GetEnumerator } } </code></pre> <p>Members that are explicit interface implementations are only visible through an instance of the interface. Thus:</p> <pre><code>X&lt;int&gt; x = new X&lt;int&gt;(); var e1 = x.GetEnumerator(); // invokes IEnumerable&lt;int&gt;.GetEnumerator // IEnumerable.GetEnumerator is not visible IEnumerable y = x; var e2 = y.GetEnumerator(); // invokes IEnumerable.GetEnumerator </code></pre> <p>Thus, in your code</p> <pre><code>X ob = new Y(); ob.add(1, 2); // X.add is visible through interface Y y = new Y(); y.add(1, 2); // compile-time error, X.add is not visible </code></pre> <blockquote> <p>Both methods don't require modifiers but when I don't use interface, like X.add() above, I need to make the implementation public. Why?</p> </blockquote> <p>Okay, it's not clear exactly what you're asking here. Access modifiers are not allowed for explicit interface implementations. This is 13.4:</p> <blockquote> <p>It is a compile-time error for an explicit interface member implementation to include access modifiers, and it is a compile-time error to include the modifiers <code>abstract</code>, <code>virtual</code>, <code>override</code>, or <code>static</code>.</p> </blockquote> <p>If a interface implementation is not marked as being an explicit interface implementation, then it must have the access modifier <code>public</code>. This is 13.4.4 (Interface mapping):</p> <blockquote> <p>Interface mapping for a class or struct <code>C</code> locates an implementation for each member of each interface specified in the base class list of <code>C</code>. The implementation of a particular interface member <code>I.M</code>, where <code>I</code> is the interface in which the member <code>M</code> is declared, is determined by examining each class or struct <code>S</code>, starting with <code>C</code> and repeating for each successive base class of <code>C</code>, until a match is located</p> <ul> <li><p>If <code>S</code> contains a declaration of an explicit interface member implementation that matches <code>I</code> and <code>M</code>, then this member is the implementation of <code>I.M</code></p></li> <li><p>Otherwise, if <code>S</code> contains a declaration of a non-static public member that matches <code>M</code>, then this member is the implementation of <code>I.M</code>.</p></li> </ul> <p>A compile-time error occurs if implementations cannot be located for all members of all interfaces specified in the base class list of <code>C</code>. </p> </blockquote> <p>So, in short, the compiler first looks for an explicit interface implementation. If it can not find one then it looks for a <strong>non-static, public</strong> member with the same signature as the method <code>M</code> being implemented. If it can not find one a compile-time error occurs. So the rules are this. To implement an interface member <code>I.M</code>:</p> <ol> <li><p>If you implement <code>I.M</code> explicitly then the syntax is </p> <p><code>return-type I.M(parameter-list)</code></p></li> <li><p>Otherwise, the syntax is</p> <p><code>public return-type M(parameter-list)</code></p></li> </ol> <p>Thus, with </p> <pre><code>interface IAdd { int Add(int x, int y) } </code></pre> <p>We can implement explicitly:</p> <pre><code>class Explicit : IAdd { int IAdd.Add(int x, int y) { return x + y; } } </code></pre> <p>or not:</p> <pre><code>class NotExplicit : IAdd { public int Add(int x, int y) { return x + y; } } </code></pre> <p>The difference is then that <code>Explicit.Add</code> is not visible unless instances of <code>Explicit</code> are typed as <code>IAdd</code>:</p> <pre><code>IAdd explicitInterface = new Explicit(); explicitInterface.Add(2, 2); Explicit explicit = new Explicit(); explicit.Add(2, 2); // compile-time error </code></pre> <p>whereas</p> <pre><code>IAdd notExplicitInterface = new NotExplicit(); notExplicitInterface.Add(2, 2); NotExplicit notExplicit = new NotExplicit(); notExplicit.Add(2, 2); // okay, NOT a compile-time error as above </code></pre> <p>Does that help?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload