What's the point of a public explicit interface and how does this differ from private?
interface IYer
{
void Hello();
}
interface INer
{
void Hello();
}
class MyClass : IYer, INer
{
public void IYer.Hello()
{
throw new NotImplementedException();
}
public void INer.Hello()
{
throw new NotImplementedException();
}
}
I'm not going to address the code above, which I believe has errors pointed out by others, but I'll answer the question itself.
With explicit interface implementation, you can support multiple interfaces that have conflicting names.
You avoid emphasizing the availability of an interface to clients, when the interface isn't important to most consumers of that class. This is because most languages in the Dotnet framework will require an explicit cast to the interface before you can use methods from explicitly implemented interfaces.
Less important, but I've used them to prevent accidental use of a method or property accessor: Using Explicit Interfaces to prevent accidental modification of properties in C#
There is no public explicit interface implementation. The only way to implement an interface explicitly is to have the method have default accessibility with the interface name prepended to the method name:
class MyClass : IYer, INer
{
//compiles OK
void IYer.Hello()
{
throw new NotImplementedException();
}
//error CS0106: The modifier 'public' is not valid for this item
public void INer.Hello()
{
throw new NotImplementedException();
}
}
This is what MSDN has to say about this:
The public keyword is not allowed on an explicit interface declaration. In this case, remove the public keyword from the explicit interface declaration.
The biggest difference is that your public explicit interfaces are not legal and will not compile. In fact, you should be getting the error, "The modifier 'public' is not valid for explicit interface implementations."
Related
I have a question while studying C#.
When I declare the interface, I usually declare it like the code below
public interface IRequireInitialization
{
void Init();
}
public class TESTManager : IRequireInitialization
{
public void Init(){ throw new NotImplementedException(); }
}
but my friend said that I should add abstract before the declaration of the interface member function.
I didn't feel any big difference in implementing the interface, what's the difference? And if there is a difference, when should I use it?
public interface IRequireInitialization
{
abstract void Init();
}
public class TESTManager : IRequireInitialization
{
public void Init(){ throw new NotImplementedException(); }
}
C# 8 introduced default interface methods. This allows to define a default implementation (body) for a method in the interface itself.
As part of this proposal they relaxed the syntax to allow modifiers for interface methods:
The syntax for an interface is relaxed to permit modifiers on its members. The following are permitted: private, protected, internal, public, virtual, abstract, sealed, static, extern, and partial.
A method in an interface is abstract by default and abstract modified just makes that explicit:
similarly, although abstract is the default on interface members without bodies, that modifier may be given explicitly.
I can have a nested contracts type for a non-generic interface:
[ContractClass(typeof(Foo.FooContracts))]
public interface IFoo
{
string Bar(object obj);
}
But it complains when I try to do the same thing with a generic interface:
[ContractClass(typeof(Foo.FooContracts<>))]
public interface IFoo<T>
{
string Bar(T obj);
}
The warning is:
The contract class Foo+FooContracts`1 and the type IFoo`1 must have the same declaring type if any.
It compiles without a warning if I get FooContracts out of the Foo class.
Why does that limitation exist for generic interfaces?
Why doesn't that limitation exist for non-generic ones?
The reason the limitation exists is that we need to copy contracts from the declaration point to the insertion points and that gets much more complicated if there are generic surrounding classes. There really is no need to have contract classes nested inside other types that I see.
This code compiles on my machine (VS2012, .NET 4.5)
[ContractClass(typeof(Foo.FooContracts<>))]
public interface IFoo<T> {
string Bar(T obj);
}
[ContractClassFor(typeof(IFoo<>))]
public class Foo {
public class FooContracts<T> : IFoo<T> {
public string Bar(T obj) {
throw new NotImplementedException();
}
}
}
I added the ContractClassForAttribute, but I can take it out.
edit: also the ContractClassForAttribute can be applied to the outer or inner class. I don't know which is correct, but neither location affects compilation
I have a class which inherits an interface. An interface member method is implemented in my class without an access modifier (so, by default it's private ) .
I am getting the error "cannot implement an interface member because it is not public".
Why it is not allowed? Can't I override the accessibility?
Here's an example of why it doesn't make sense to be able to override the visibility:
interface someI
{
void doYourWork();
}
public class A : someI
{
public void doYourWork()
{
//...
}
}
public class B : someI
{
private void doYourWork()
{
//...
}
}
void Main()
{
List<someI> workers = getWorkers();
foreach(var worker in workers)
worker.doYourWork();
}
What happens when your worker is of type B? You're calling a method as if it were public, but it's a private method. If you want this functionality, then it's not really a private method is it?
If you only want it to be public when referenced through your interface, then you can define it as such:
public class B : someI
{
void someI.doYourWork()
{
//...
}
}
And you end up with this:
var b = new B();
b.doYourWork(); // Not accessible
((someI)b).doYourWork(); // Accessible
Methods have to be implemented public because they have to be callable through the interface, thus from where the interface is accessible as a type.
You have a few options here to "change" the visibility of that method. Given:
public interface IFoo
{
bool IsFoo();
}
A. Implement the method explicitly
public class Foo : IFoo
{
bool IFoo.IsFoo() { return true; }
}
The method will only be available through the interface (IFoo in this case.)
B. Change the visibility of the interface
Define the interface as internal instead of public. As a consequence, however, Foo will have to be internal too.
Requiring that an interface implementation be public is simply a logical requirement. When you implement an interface, you're telling the compiler "Hey I implement every method on this interface". So making the method private makes it no longer accessible - and logically not implemented. Interfaces serve as a contract to code that uses your object saying you can always call any method defined in the interface on my object. If the implementing method were private, that would not longer be true.
If you want to hide your implementation from, say Intellisense, then you can simply implement the method explicitly as #Bryan mentions.
I'm curious to know why the implementation of my interface in the abstract base class does not satisfy the the requirements in sub-classes. Here's an example:
public interface IBase { }
public interface IConcrete : IBase { }
public interface IBaseManager<out T>
where T : IBase
{
T Create();
IEnumerable<T> SelectAll();
}
public interface IConcreteManager : IBaseManager<IConcrete> { }
public abstract class Base : IBase { }
public class Concrete1 : Base, IConcrete { }
public abstract class BaseManager<T> : IBaseManager<T> where T : class, IBase
{
#region IBaseManager<T> Members
public T Create()
{
throw new NotImplementedException();
}
public IEnumerable<T> SelectAll()
{
throw new NotImplementedException();
}
#endregion
}
public class ConcreteManager : BaseManager<Concrete>, IConcereteManager
{
//error occurs here
}
This is the error that is being generated:
'ConsoleApplication4.ConcreteManager' does not implement interface member 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()'.
'ConsoleApplication4.BaseManager<ConsoleApplication4.Concrete>.Create()' cannot implement 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()' because it does not have the matching return type of 'ConsoleApplication4.IConcrete'.
If I add these methods to the ConcreteManager class, everything is fine and the compiler is happy.
public new IConcrete Create()
{
return base.Create();
}
public new IEnumerable<IConcrete> SelectAll()
{
return base.SelectAll();
}
If simply returning what the methods from the base class return is sufficient, why do the methods have to be added? Why can't the compiler call the methods in the base class?
As John points out correctly, the C# language does not support return type covariance. Neither does the CLR, so even if the language supported it, the only way we could actually implement the feature would be to silently generate exactly the code you've had to add yourself.
The small benefit afforded to developers of avoiding having to write those stub methods really does not justify the considerable cost of doing the more general covariance feature, so we've never done it.
It looks like you're assuming return type covariance, since ConcreteManager (as an IConcreteManager) expects both Create() and SelectAll() methods with a return type of IConcrete and IEnumerable<IConcrete> respectively, which the base class does not provide.
You are getting those errors because C# does not support return type covariance.
When you implement an interface/abstract class, you must use the same signature. See here
Don't let the generics throw you off, this is no different than if there were no generics.
I can't do this
interface InterfaceA
{
void MethodA();
}
class ClassA : InterfaceA
{
virtual void InterfaceA.MethodA()
// Error: The modifier 'virtual' is not valid for this item
{
}
}
Where the following works
class ClassA : InterfaceA
{
public virtual void MethodA()
{
}
}
Why? How to circumvent this?
I think this is because when a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface.
So making something 'virtual' really does not make sense in this case, since virtual means that you intend to override it in an inherited class. Implementing an interface explicitly and making it virtual would be contradictory. Which also may be why the compiler disallows this.
To work around it I think csharptest.net's or Philip's answer sounds like it would do the trick
It is part of the C# language specification:
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 abstract, virtual, override, or static.
According to C# language spec:
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
abstract, virtual, override, or
static.
You can "get around" it only by calling your virtual method from the explicit interface implementation.
You have to do something like this:
interface InterfaceA
{
void MethodA();
}
class ClassA : InterfaceA
{
void InterfaceA.MethodA()
{ MethodB(); }
protected virtual void MethodB()
{
}
}
Often this is a superior approach anyway as the internal method may change signature without changing the interface. Take a more real-word example:
interface IOrderDetails
{
void PlaceOrder();
}
//Sometime later you extend with:
interface IOrderDetails2 : IOrderDetails
{
void PlaceOrder(IUser user);
}
//Implementation
class Order : IOrderDetails, IOrderDetails2
{
static readonly IUser AnonUser;
void IOrderDetails.PlaceOrder()
{ OnPlaceOrder(AnonUser); }
void IOrderDetails2.PlaceOrder(IUser user)
{ OnPlaceOrder(user); }
protected virtual void OnPlaceOrder(IUser user)
{
}
}
Here you can see as the IOrderDetails2 was added we can safely refactor the existing virtual method (thus generating compile-time errors for derivations). Additionally this often allows you to provide common functionality, logging, and exception handling in the base implementation class...
You cannot use the virtual modifier with the static, abstract, private or override modifiers.
default modifier is private