C# interface property implementation - c#

interface IAlpha
{
IBeta BetaProperty { get; set; }
}
interface IBeta
{
}
class Alpha : IAlpha
{
public Beta BetaProperty { get; set; } // error here
}
class Beta : IBeta
{
}
'InterfaceTest.Alpha' does not implement interface member 'InterfaceTest.IAlpha.BetaProperty'. 'InterfaceTest.Alpha.BetaProperty' cannot implement 'InterfaceTest.IAlpha.BetaProperty' because it does not have the matching return type of 'InterfaceTest.IBeta'.
My question is why is a property implementation restricted to the very same type. Why can't I use the derived type instead?

You have to implement the exact same interface. For example, this should be valid:
IAlpha alpha = new Alpha();
alpha.BetaProperty = new SomeOtherIBetaImplementation();
... but that wouldn't work with your code which always expects it to be a Beta, would it?
You can use generics for this though:
interface IAlpha<TBeta> where TBeta : IBeta
{
TBeta BetaProperty { get; set; }
}
...
public class Alpha : IAlpha<Beta>
Of course, that may be overkill - you may be better just using a property of type IBeta in Alpha, exactly as per the interface. It depends on the context.

An interface declares a set of methods the class will have, so anyone using that interface knows what to expect.
So, if you're implementing that interface, you must implement the exact interface, so all the other users get what they expected.

Related

How to redefine a property in C# through interface inheritance?

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.

How to get base class object from closed constructed class in C#

Just another small C# training app, and just another Compilation Error, but it cannot just go away from me... I am just wondering, what I am doing wrong here:
public abstract class Material
{
}
public abstract class Cloth<T> where T:Material
{
public T Prop { get; set; }
}
public class Cotton : Material
{
}
public class Dress<T> : Cloth<T> where T : Material
{
}
public class Test
{
private Cloth<Material> cloth;
public Test()
{
/* below won't compile */
cloth = new Dress<Cotton>();
}
}
I want to get the base class object from a closed constructed class. Anyone ?
When trying to compile I get the error:
Cannot implicitly convert type Dress<Cotton> to Cloth<Material>
What you want to achieve is called covariance (see the following article for samples).
Unfortunately, there's no variance support for classes: it's restricted to interfaces and delegates.
Thus and alternatively, you might design an interface called ICloth<T> with T covariant:
public interface ICloth<out T>
{
T Prop { get; set; }
}
And implement it in any of your possible cloths, including Cloth<T>.
Now type cloth as ICloth<T> and your assignment should work (i.e. cloth = new Dress<Cotton>();), because Dress<Cotton> is ICloth<out T>, which is an interface with a T covariant generic parameter.
Learn more about generic interface with variance in the following article on MSDN.

Why I cannot implement an interface on a class replacing an interface with a concrete type? [duplicate]

This question already has answers here:
The return type of the members on an Interface Implementation must match exactly the interface definition?
(6 answers)
Does C# support return type covariance?
(9 answers)
Closed 8 years ago.
Why can I not do the following?
public class TestClass : TestInterface
{
public ClassX Property { get; private set; }
}
public interface TestInterface
{
InterfaceX Property { get; }
}
public interface InterfaceX
{
}
public class ClassX : InterfaceX
{
}
The TestInterface Property is readonly, thus can only return InterfaceX as per the contract.
However, I get this compiler error:
'TestClass' does not implement interface member
'TestInterface.InterfaceX'. 'TestClass.InterfaceX' cannot implement
'TestInterface.InterfaceX' because it does not have the matching
return type of 'InterfaceX'.
It does not have the matching type but it has a subclass of that type.
I don't know the spec offhand, but I'm sure there's one that explicitly states that return types must match exactly for interface implementations. The closest I can find is 13.4.4:
For purposes of interface mapping, a class member A matches an interface member B when:
A and B are methods, and the name, type, and formal parameter lists of A and B are identical.
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).
If "type" above means "return type" that would indicate that the return type cannot change.
You could, however, change the return type and explicitly implement the interface with the right return type:
public class TestClass : TestInterface
{
public ClassX InterfaceX { get; private set; }
InterfaceX TestInterface.InterfaceX { get { return InterfaceX; } }
}
UPDATE
According to Eric Lippert it seems to be a CLR limitation, not just a C# one.
You mentioned that you want to expose a reduced set but you want all the functionality internal to the class -- that's not what you want to use an interface for. An interface should only be about your reduced set contract, not also magically function as a full set internally, not without another helper property.
But, there is a way around this limitation while still communicating the contract a little.
interface IExpose<IToolType> where IToolType : ITool
{
IToolType Handler { get; set; }
}
class Expose : IExpose<Tool>
{
public Tool Handler { get; set; }
}
interface ITool
{
}
class Tool : ITool
{
}

How to force multiple Interfaces to include the same properties?

I am trying to figure out a way to force all of my Interfaces to include properties of the same name/type.
For example: I have two Interfaces; IGetAlarms and IGetDiagnostics. Each of the Interfaces will contain properties that are specific to the Interface itself, however I want to force the two Interfaces (and all other Interfaces that may be added later) to include properties of the same name. So, the result may look something like the this:
interface IGetAlarms
{
string GetAlarms();
DateTime LastRuntime { get; set; }
}
interface IGetDiagnostics
{
string GetDiagnostics();
DateTime LastRuntime { get; set; }
}
Notice that both Interfaces include a DateTime property named LastRuntime.
I would like to know if there is some way I can force other Interfaces that will be added later to include the DateTime LastRuntime property. I have naively attempted to have all my Interfaces implement another Interface (IService) - which includes the LastRuntime property. However, that doesn't solve my problem as that simply forces the class to implement the property - not all the Interfaces.
Thanks.
An interface can inherit from other interfaces.
interface IDerived : IBase
{
string Foo { get; set; }
}
interface IBase
{
DateTime LastRunDate { get; set; }
}
Any class deriving from IDerived will have to implement the methods/properties of IBase as well.
class Derived : IDerived
{
#region IDerived Members
public string Foo { get; set; }
#endregion
#region IBase Members
public DateTime LastRunDate {get;set;}
#endregion
}
If I understand your question correctly, you want to force a class to implement a number of different interfaces, the list of interfaces will grow with time but will have some properties in common.
The common property part you have solved with your IService interface. Something like this, I presume
interface IService
{
DateTime LastRuntime { get; set; }
}
interface IGetAlarms : IService
{
string GetAlarms();
}
interface IGetDiagnostics : IService
{
string GetDiagnostics();
}
The growing list of interfaces that a class will have to implement you can also solve in a similar fashion. Create a "composite" interface which inherits from all the interfaces you wish your class to implement
interface IComposite : IGetAlarms, IGetDiagnostics {}
class MyClass : IComposite
{
...
}
When you let the IComposite interface inherit a new interface, the class will have implement the new interface too.
EDIT
In response to your clarification; in that case you should not share the specification of the LastRuntime property, but declare it in each individual interface. In the implementing class you can use Explicit interface member implementation
class MyClass : IComposite
{
DateTime IGetAlarms.LastRuntime { get; set; }
DateTime IGetDiagnostics.LastRuntime { get; set; }
...
}
However, AFAIK it is not possible to force the implementing class to explicitly implement each individual interface
It really depends on exactly what you need the interface for. You can use generics to enforce the implementation of a specified pattern, but you can't enforce the implementation of each individually if they all have identical signatures.
public interface IA<T> where T: class
{
void DoIt(T ignore = null);
}
public interface IB : IA<IB>
{
}
public interface IC : IA<IC>
{
}
That would force the following class to implement each separately:
public class D : IB, IC
{
public void DoIt(IB ignore = null) { }
public void DoIt(IC ignore = null) { }
}
It's the "T ignore" parameter that forces each one to be implemented separately, and since it has a default value, you can just ignore that parameter unless calling it using reflection.
But obviously this doesn't work with properties, so they would have to be implemented using getter/setter methods.

Contravariance and Entity Framework 4.0: how to specify EntityCollection as IEnumerable?

I have specified a couple of interfaces, which I am implementing as entities using Entity Framework 4. The simplest demonstration code I can come up with is:
public class ConcreteContainer : IContainer
{
public EntityCollection<ConcreteChild> Children { get; set; }
}
public class ConcreteChild : IChild
{
}
public interface IContainer
{
IEnumerable<IChild> Children { get; set; }
}
public interface IChild
{
}
I receive the following compiler error from the above:
'Demo.ConcreteContainer' does
not implement interface member
'Demo.IContainer.Children'.
'Demo.ConcreteContainer.Children'
cannot implement
'Demo.IContainer.Children'
because it does not have the matching
return type of
'System.Collections.Generic.IEnumerable'
My current understanding is that this is because IEnumerable (which is implemented by EntityCollection) is covariant but presumably not contravariant:
This type parameter is covariant. That is, you can use
either the type you specified or any type that is more
derived. For more information about covariance and contravariance,
see Covariance and Contravariance in Generics.
Am I correct, & if so, is there any way I can achieve my goal of specifying the IContainer interface purely in terms of other interfaces rather than using concrete classes?
Or, am I misunderstanding something more fundamental?
The generic variance in .NET 4 is irrelevant here. The implementation of an interface has to match the interface signature exactly in terms of types.
For example, take ICloneable, which looks like this:
public interface ICloneable
{
object Clone();
}
It would be nice to be able to implement it like this:
public class Banana : ICloneable
{
public Banana Clone() // Fails: this doesn't implement the interface
{
...
}
}
... but .NET doesn't allow this. You can sometimes use explicit interface implementation work around this, like so:
public class Banana : ICloneable
{
public Banana Clone()
{
...
}
object ICloneable.Clone()
{
return Clone(); // Delegate to the more strongly-typed method
}
}
However, in your case you can't ever do that. Consider the following code, which would be valid if ConcreteContainer was considered to implement IContainer:
IContainer foo = new ConcreteContainer();
foo.Children = new List<IChild>();
Now your property setter is actually only declared to work with EntityCollection<ConcreteChild>, so it clearly can't work with any IEnumerable<IChild> - in violation of the interface.
As far as I understand, you must implement an interface - you can't assume that a covariant/contra-variant member would be picked up as a substitute.
Even if it was permissible, note that setter for children is an issue. Because it will allow to set property of type EntityCollection<ConcreteChild> with value of any other type such as List<ConcreteChild> or EntityCollection<ConcreteChild2> because both are implementing IEnumerable<IChild>.
In current design, I will implement IContainer privately in ConcreteContainer and check the input value in IEnumerable.Children setter for a compatible type. Another way to approach this design is to have generic interfaces such as:
public interface IContainer<T> where T:IChild
{
IEnumerable<T> Children { get; set; }
}
So you need to implement this interface, right?
public interface IContainer
{
IEnumerable<IChild> Children { get; set; }
}
But in the real class, you want the property to be of type EntityCollection<ConcreteChild>. Here’s how you can do this:
public class ConcreteContainer : IContainer
{
// This is the property that will be seen by code that accesses
// this instance through a variable of this type (ConcreteContainer)
public EntityCollection<ConcreteChild> Children { get; set; }
// This is the property that will be used by code that accesses
// this instance through a variable of the type IContainer
IEnumerable<ConcreteChild> IContainer.Children {
get { return Children; }
set {
var newCollection = new EntityCollection<ConcreteChild>();
foreach (var item in value)
newCollection.Add(item);
Children = newCollection;
}
}
}

Categories