Is there a specific reason why the following is not possible?
class ClassOfInts : IHaveInts
{
public MyInt IntHolder { get; }
// This solves my use case but i'm unsure why this is necessary
// IInt IHaveInts.IntHolder { get => IntHolder; }
}
interface IHaveInts
{
IInt IntHolder { get; }
}
class MyInt : IInt
{
public int TheInt { get; }
}
interface IInt
{
int TheInt { get; }
}
I would think that the above code successfully implements IHaveInts since MyInt implements IInt.
Is there a specific reason why the following is not possible?
Well, the short answer is: "because the C# specification doesn't allow it". Longer answers typically involve some amount of speculation as to what was in the thought process of the C# language designers. That makes such questions primarily opinion based.
However, they did make a deliberate choice that interface members have to be implemented precisely as declared, and that choice is why you can't do that. A likely reason behind that choice is that they would have to special-case read-only properties, because allowing the property to be implemented that way for a writeable property would be unsafe. Were they to allow that, you'd be able to assign any IInt value to the property which expects only MyInt values.
That said, depending on what you're actually trying to do, you might be able to use generic type variance to support your scenario. This will compile fine:
public class ClassOfInts : IHaveInts<MyInt>
{
public MyInt IntHolder { get; }
}
public interface IHaveInts<out T> where T : IInt
{
T IntHolder { get; }
}
Declared that way, the following works fine:
static void M()
{
IHaveInts<IInt> haveInts = new ClassOfInts();
}
This is semantically equivalent to what you were originally trying to do. That is, when using the interface type, you have a property of type IInt, but you want to implement that property with a member that returns a value of type MyInt.
Related
I have an interface 'IBase' that specifies a nullable int. A later interface 'IDerived' hides the nullable int and 'redefines' it as non-nullable.
interface IBase
{
int? Redefineable { get; set; }
}
interface IDerived : IBase
{
new int Redefineable { get; set; }
}
The class that implements these interfaces must explicitly implement the hidden property, however it's private so the client can't see it.
class TheClass : IDerived
{
public int Redefineable { get; set; }
int? IBase.Redefineable { get; set; }
}
However, even though it's a private property, I can still access it through the IBase interface!
var o = new TheClass();
o.Redefineable = 1; // ok
var hack = o as IBase;
hack.Redefineable = null; // uh!
This seems like some kind of violation of C# access modifiers, but either way it isn't really what I had in mind for redefining (not just hiding) a property. It's correct in the sense that it does what you're asking, get an IBase interface which has a nullable int but this is non-intuitive to the client who could then modify the wrong version of the property.
What I really want, is that if the client accesses IBase.Redefinable, then it behaves as if it's accessing the IDerived.Redefinable property, the 'real' property of TheClass. That way it's actually redefined, as in back through the hierarchy.
class TheClass : IDerived
{
public int Redefineable { get; set; }
int? IBase.Redefineable {
get {
// redirect to redefined property
return this.Redefineable;
}
set
{
// stop client setting it to null
if (!value.HasValue)
throw new InvalidOperationException();
// redirect to redefined property
this.Redefineable = value.Value;
}
}
}
This just feels like a hack, almost as if I'm missing something, so I want to ask if anyone knows a better/alternative way to implement re-definable properties?
However, even though it's a private property, I can still access it through the IBase interface!
It's not a private property. It's just a property using explicit interface implementation. That means it's public through the interface, but only available through the interface. Explicit interface implementation is mostly designed to make it feasible to implement "contradictory" interfaces, as well as being used to "discourage" (but not prohibit) the use of some interface methods. It's not meant to give the impression that the members don't exist at all.
Fundamentally, it sounds like you shouldn't be using inheritance here - if you don't want something to be able to act as an IBase, you shouldn't inherit from IBase.
Related Post: C# interface method ambiguity
Code from the same source:
private interface IBase1
{
int Percentage { get; set; }
}
private interface IBase2
{
int Percentage { get; set; }
}
private interface IAllYourBase : IBase1, IBase2
{
}
private class AllYourBase : IAllYourBase
{
private int _percentage;
public int Percentage
{
get { return _percentage; }
set { _percentage = value; }
}
}
private void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; // Fails to compile. Ambiguity between 'Percentage' property.
}
(But does not answer my question -- "WHY the contracts become ambiguous? " )
Given:
Interface is a contract that the implementing class MUST abide with.
If two (or more) interfaces ask for the same contract and a interface passes them 'forward' and then class implements both of them and ACCEPTS that the common contracts should serve as just one contract for the implementing classes (by not providing an explicit implementation). Then,
Why does compiler shows 'ambiguity' warning over the common contracts?
Why the compiler fails to compile on trying to access the ambiguous contract through interface( iayb.Percentage) ?
I would like to know what benefit compiler is serving with this restriction?
Edit: Providing a real world use case where I would like to use contracts across interfaces as one contract.
public interface IIndexPriceTable{
int TradeId{get;}
int IndexId{get;}
double Price{get;}
}
public interface ILegPositionTable{
int TradeId {get;}
int LegId {get;}
int Position {get;}
}
public interface ITradeTable {
int TradeId{get;}
int IndexId{get;}
int LegId{get;}
//others
}
public interface IJoinedTableRecord : IIndexPriceTable, ILegPositionTable, ITradeTable {
//Just to put all contracts under one interface and use it as one concrete record, having all information across different tables.
}
Why would I like to have 3-TradeId, 2-LegId, 2-IndexId in my joined table record?
The solution is to define a property Percentage again with new keyword like this:
private interface IBase1
{
int Percentage { get; set; }
}
private interface IBase2
{
int Percentage { get; set; }
}
private interface IAllYourBase : IBase1, IBase2
{
new int Percentage { get; set; }
}
private class AllYourBase : IAllYourBase
{
private int _percentage;
public int Percentage
{
get { return _percentage; }
set { _percentage = value; }
}
}
private void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; //OK
}
Notice:
C# approach to interfaces is very different to approach plan by Bjarne StrouStrup in C++14. In C# you have to claim, that the class implement interface by modifying class itself while in C++14 it only needs to have methods which correspond to interface definition. Thus the code in C# have more dependencies that code in C++14.
Because the interface IAllYourBase does not declare the Percentage property itself.
When you assign an instance of AllYourBase to a variable of IAllYourBase the compiler needs to output a call to either IBase1.Percentage or IBase2.Percentage:
callvirt instance int32 IBase1::get_Percentage()
or
callvirt instance int32 IBase2::get_Percentage()
These are different members on different types and just because they have the same signature doesn't mean they are interchangeable.
In your real world situation you might need finer grained interfaces that define the common properties.
Because the compiler can't figure out which base interface implementation (IBase1.Percentage or IBase2.Percentage) you're trying to access, because your IAllYourBase interface takes after both of them and both of them each have their own Percentage property.
Put it this way: just because two interfaces have a property with the same name and type doesn't mean that the property is intended to work the same way in both interfaces. Even if a common interface inherits from two interfaces with identical members, the compiler can't just combine two seemingly identical properties into one, because they are members of two different contracts.
The line int percentage = iayb.Percentage; has no idea it's dealing with an AllYourBase class, just that whatever it is, it implements the IAllYourBase interface.
So suppose I tried to execute the same statement using my DoubleBase class:
private class DoubleBase : IAllYourBase
{
int IBase1.Percentage { get; set; } = 10;
int IBase2.Percentage { get; set; } = 20;
}
To what value does int percentage get set?
I see your point. I guess the main benefit from this compiler restriction is that it's better to have one, then to not. I.e. there is more harm then your unintentional interface clush will be ignored, then benefit (if there is any) from this strange case there you want such behaviour.
BTW any real-world scenario there desired behaviour will be so much useful?
If an interface inherits two other interfaces that are going to have like-named members, then one of two conditions has to apply:
Both interfaces inherit the same member from some other interface. The other interface will have to be public, but one can document that it exists purely to be inherited, and that consumers are not expected to declare variables or parameters of its type.
The interface which inherits the other interfaces declares as `new` its own member of that same name. This is a good approach when one interface declares a read-only property and another declares a write-only property of the same name; the interface that combines those two interfaces can declare a read-write property whose implementation would be expected to use the read-only property's "getter" and the write-only property's "setter". I'm not sure that it would be good in many other situations, though.
If one does not do one of those things, it's probably best that the compiler not try to guess. Imagine that one has interfaces IListOfDigits, whose Add method appends an integer 0-9 to the list, and IBigNumber, whose Add method adds a number arithmetically. One also has an interface IListOfDigitsRepresentingBigNumber which inherits both. Given an IListOfDigitsRepresentingBigNumber called myThing, holding the digits "5,4,3,2", what should be the effect of myThing.Add(1)? Should it change myThing to hold "5,4,3,2,1" (the effect of IListOfDigits.Add) or "5,4,3,3" (the effect of IBigNumber.Add)? If one does either of the above things, the compiler will have no difficulty figuring out which Add method to use. Otherwise, if both methods can accept an int it won't have a clue.
Incidentally, generics and overloading pose an interesting case. If a IFoo<T,U> has members void Bar(T param) and void Bar(U param), one cannot declare a class as implementing IFoo<int,int>. On the other hand, one can declare a class Foo<T,U> as implementing IFoo<T,U>, and then declare some other class as inheriting from Foo<int,int>, because even if T and U refer to the same type, the compiler would still resolve overloads using T and U.
According to CSharp Language Specification.
An interface defines a contract that can be implemented by classes and
structs. An interface does not provide implementations of the members
it defines—it merely specifies the members that must be supplied by
classes or structs that implement the interface.
So I a have this:
interface ITest
{
IEnumerable<int> Integers { get; set; }
}
And what I mean is. "I have a contract with a property as a collection of integers that you can enumerate".
Then I want the following interface Implementation:
class Test : ITest
{
public List<int> Integers { get; set; }
}
And I get the following compiler error:
'Test' does not implement interface member 'ITest.Integers'.
'Test.Integers' cannot implement 'ITest.Integers' because it does not
have the matching return type of
'System.Collections.Generic.IEnumerable'.
As long as I can say my Test class implement the ITest contract because the List of int property is in fact an IEnumerable of int.
So way the c# compiler is telling me about the error?
FYI, the feature you want is called "virtual method return type covariance", and as you have discovered, it is not supported by C#. It is a feature of other object-oriented languages, like C++.
Though we get requests for this feature fairly frequently, we have no plans to add it to the language. It is not a terrible feature; if we had it, I'd use it. But we have many reasons not to do it, including that it is not supported by the CLR, it adds new and interesting failure modes to versionable components, Anders does not think it is a very interesting feature, and we have many, many higher priorities and a limited budget.
Incidentally, though people ask us for virtual method return type covariance all the time, no one ever asks for virtual method formal parameter type contravariance, even though logically they are essentially the same feature. That is, I have a virtual method/interface method M that takes a Giraffe, and I would like to override it/implement it with a method M that takes an Animal.
You can't do this because you'd have a major problem on your hand depending on the implementation if this were allowed. Consider:
interface ITest
{
IEnumerable<int> Integers { get; set; }
}
class Test : ITest
{
// if this were allowed....
public List<int> Integers { get; set; }
}
This would allow:
ITest test = new Test();
test.Integers = new HashSet<int>();
This would invalidate the contract for Test because Test says it contains List<int>.
Now, you can use explicit interface implementation to allow it to satisfy both signatures depending on whether it's called from an ITest reference or a Test reference:
class Test : ITest
{
// satisfies interface explicitly when called from ITest reference
IEnumerable<int> ITest.Integers
{
get
{
return this.Integers;
}
set
{
this.Integers = new List<int>(value);
}
}
// allows you to go directly to List<int> when used from reference of type Test
public List<int> Integers { get; set; }
}
Simple fact is, if an interface says:
IInterface{
Animal A { get; }
}
Then an implementation of that property must match the type exactly. Trying to implement it as
MyClass : IInterface{
Duck A { get; }
}
Does not work - even though Duck is an Animal
Instead you can do this:
MyClass : IInterface{
Duck A { get; }
Animal IInterface.A { get { return A; } }
}
I.e. provide an explicit implementation of the IInterface.A member, exploiting the type relationship between Duck and Animal.
In your case this means implementing, the getter at least, ITest.Integers as
IEnumerable<int> ITest.Integers { get { return Integers; } }
To implement the setter, you will need to cast optimistically or use .ToList() on the input value.
Note that the use of A and Integers inside these explicit implementations is not recursive because an explicit interface implementation is hidden from the public view of a type - they only kick in when a caller talks to the type through it's IInterface/ITest interface implementation.
You need 13.4.4 from the specification:
For purposes of interface mapping, a class member A matches an interface member B when:
• A and B are properties, the name and type of A and B are identical, and A has the same accessors as B (A is permitted to have additional accessors if it is not an explicit interface member implementation).
Additionally, your belief that List<int> Integers { get; set; } satisfies the contract of IEnumerable<int> Integers { get; set; } is false. Even if the specification were somehow relaxed to not require that the return types be identical, note that a property of type List<int> with a public setter is not anywhere near the same as a property of type IEnumerable<int> with a public setter because to the latter you can assign an instance of int[], but to the former you can not.
You can do something like this:
interface ITest
{
IEnumerable<int> Integers { get; set; }
}
class Test : ITest
{
public IEnumerable<int> Integers { get; set; }
public Test()
{
Integers = new List<int>();
}
}
Because Test is not an ITest. Why ? With an ITest you can set an array to the property Integers. But you can't with a Test.
With .net 4.0 you can do things like that (covariance and contra-variance) but not exactly that, it's incorrect in every language.
Greetings everyone...
If I have the following interface:
interface IMyInterface
{
int property { get; set; }
}
And the following implementation:
class MyClass : IMyInterface
{
// anything
}
How can I hide the set method of property from the instances of MyClass... In other words, I don't want the set method of property to be public, is that possible?
It would be easy to do with abstract class:
abstract class IMyInterface
{
int property { get; protected set; }
}
Then I could only set the property within the class that implements the abstract class above...
Don't have the set in the interface to begin with. You can still implement it as private.
You can't "hide" it, it's part of the contract. If you don't want it to be part of the contract, don't define it.
If you use the following interface the set method will be unavailable when classes are manipulated via the interface:
interface IMyInterface
{
int property { get; }
}
You could then implement the class like this:
class MyClass : IMyInterface
{
int property { get; protected set; }
}
If some implementations will only implement some parts of an interface, it may be a good idea to subdivide the interface into the parts which each implementation will either implement completely or not at all, and then define interfaces which inherit all the common combinations of them. Adapting your example:
interface IMyReadableInterface
{
int property { get; }
}
interface IMyFullInterface : IMyReadableInterface
{
new int property { get; set; }
}
Classes which want to support read-write access should implement IMyFullInterface; those which want to only support read access should only implement IMyReadableInterface. This segregation will not require any extra work for implementations of either interface which are written in C# and implement property implicitly. Code which implements property in VB, or explicitly implements property in C#, will have to define two implementations of property--a read-only one and a read-write one, but such is life. Note that while one could define an IMyWritableInterface which just had a setter, and have IMyFullInterface inherit both IMyReadableInterface and IMyWritableInterface, IMyFullInterface would still have to define a read-write property of its own, and when using explicit implementation one would then have to define three properties (I really don't understand why C# can't use a read-only and write-only property together as thought they were a read-write property, but it can't).
Assuming you need the setter to be part of the interface but for some reason it does not make sense for it to be used on a particular implementer (in this case MyClass) you can always throw an exception in the setter (such as an InvalidOperationException). This will not protect you at compile time, only at run time. It is a bit strange though, as code that operates on the interface has no idea whether calling the setter is allowed.
There are certainly cases where you want the interface to have a set and then hide it in some concrete class.
I believe the code below shows what we want to accomplish. I.e. the implementation hides the setter, but any IMyInterface aware component will have access to it.
public static void Main()
{
var myClass = new MyClass();
myClass.Property = 123; // Error
((IMyInterface)myClass).Property = 123; // OK
}
It's basically the same pattern you often see for IDisposable.Dispose() where you have an Explicit Interface Implementation. Here's an example for completeness.
public interface IMyInterface
{
int Property { get; set; }
}
public class MyClass : IMyInterface, IDisposable
{
public int Property { get; private set; }
int IMyInterface.Property
{
get => Property;
set => Property = value;
}
void IDisposable.Dispose() {}
}
Too much typing :(
C# doesn't help us much here. Ideally, it would be possible to have an explicit interface implementation for the setter:
// In C# 10 maybe we can do this instead:
public class MyFutureClass : IMyInterface
{
public int Property { get; IMyInterface.set; }
}
See C# feature proposal here.
There is no protected or private in interface, everything is public. Either you don't define any set or use it as public.
Why doesnt this work?
public class ClassOptions {}
public interface Inode {
ClassOptions Options {get;}
}
public class MyClass : Inode {
public ClassOptions Options { get; set; }
}
public class ClassDerivedOptions : ClassOptions {
}
public class MyDerivedClass : Inode {
public ClassDerivedOptions Options { get; set; } << does not implement INode...
}
[ the compiler message tells me why it breaks but i'd like to know the reasoning behind why the compiler doesnt let this through - also if there are any work arounds? - thanks]
It doesn't work because the INode interface explicitly calls for an Options property of type ClassOptions. C# doesn't support return type covariance (which is what you're asking for in this case).
For what it's worth, there's also a language feature request on Microsoft Connect specifically for return type covariance:
Need covariant return types in C# / all .NET languages
If you look at the page, they also mention that the common work-around is to use Explicit Interface Implementation:
public class MyDerivedClass : INode
{
public ClassDerivedOptions Options { get; set; }
public ClassOptions INode.Options { get { return Options; } }
}
As Justin notes, the feature you want is called "return type covariance" and it is not supported in C#, or, for that matter, in the CLR type system.
Though it is frequently requested, it is extremely unlikely (*) that this feature will be implemented any time soon. Since it is not supported in the CLR, in order to implement it we would simply have to generate all the helper methods that do the call forwarding for you. Since you can already do that "manually" with a small amount of code, there is little value added by the compiler doing it for you. (And as another question today notes, people sometimes get confused or irritated when the compiler generates a method to do interface forwarding on your behalf.)
Don't get me wrong; I can see how it comes in handy, and I've used this feature in C++. But every time it has come up in a C# program, I've found I can work around its absence pretty easily.
(*) Of course five years ago I would have said exactly the same thing about named and optional parameters, and now they're in C# 4. It is possible for an unlikely feature to be implemented, but the demand has to be pretty darn high.
It doesn't work because an interface defines a contract and when you implement this contract method signatures must match exactly. A possible workaround is to use a generic interface:
public class ClassOptions
{ }
public class ClassDerivedOptions : ClassOptions
{ }
public interface INode<T> where T : ClassOptions
{
T Options { get; }
}
public class MyClass : INode<ClassOptions>
{
public ClassOptions Options { get; set; }
}
public class MyDerivedClass : INode<ClassDerivedOptions>
{
public ClassDerivedOptions Options { get; set; }
}
The standard way to deal with this situation is to implement the interface explicitly:
public class MyDerivedClass : Inode {
// New, more specific version:
public ClassDerivedOptions Options { get; set; }
// Explicit implementation of old, less specific version:
ClassOptions Inode.Options
{
get { return Options; }
}
}
This is how most old IList implementations worked before generics, for example: specifying a more specific T this[int index] property and then explicitly implementing object IList.this[int index], throwing an exception when the set got called with an object of the wrong type.
In the example code you posted, you don't even need an explicit set, as that is not a member of your Inode interface.