Say I have a class like...
public abstract class Base
{
public abstract IAttributes Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And a class like this...
public class ImplementAttributes : IAttributes
{
public string GlobalId { get; set; } = "";
public string LocalId { get; set; } = "";
// Other Properties and Methods....
}
And then I implement it like...
public class Derived: Base
{
public new ImplementAttributes Attributes { get; set; }
}
Now, I realise the above will not work because I can't override the property Attributes and if I hide it with new then the following bellow is null because the Base property does not get written.
public void DoSomethingWithAttributes(Base base)
{
var Foo = FindFoo(base.Attributes.GlobalId); // Null because its hidden
}
But I would like to be able to access the Base and Derived property attributes eventually like Above.
Can this be accomplished? Is there a better way?
You can use generics:
public abstract class Base<T> where T: IAttributes
{
public abstract T Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And
public class Derived: Base<ImplementAttributes>
{
public override ImplementAttributes Attributes { get; set; }
}
And then:
public void DoSomethingWithAttributes<T>(Base<T> b) where T : IAttributes
{
var Foo = FindFoo(b.Attributes.GlobalId);
}
You can pass Derived instances without specifying a type parameter explicitly:
Derived d = new Derived();
DoSomethingWithAttributes(d);
Related
I have some abstract base classes to be used on multiple implementations.
Base classes:
public abstract class BaseX
{
public string A { get; set; }
}
public abstract class BaseY : BaseX
{
public string B { get; set; }
}
For each use case, I want to create from these base classes specific classes like:
public abstract SpecificX : BaseX
{
public string C { get; set; }
}
public abstract SpecificY : BaseY
{
public string D { get; set; }
}
All classes that derive from SpecificY should contain all the properties A, B, C, D.
My problem now is, that SpecificY doesn't have the property C from SpecificX, because I cannot do multiple inheritance like
public abstract SpecificY : BaseY, SpecificX
My only idea would be to use Interface like this:
public Interface ISpecificX
{
string C { get; set; }
}
public abstract SpecificX : BaseX, ISpecificX
{
public string C { get; set; }
}
public abstract SpecificY : BaseY, ISpecificY
{
public string D { get; set; }
public string C { get; set; } <== redundancy
}
But then I'd need to implement C twice. And as soon as C is becoming more than a simple Property, things get ugly. Is there a better way to create this structure?
Thanks in advance,
Frank
I would strongly suggest to favour composition over inhertiance - as propsed by the GoF. This way you do not inherit a given class, but just use an instance of it. Then you can easily have all your properties without any duplication:
class BaseX { ... }
class BaseY { ... }
class SpecificY : BaseY
{
private readonly SpecificX b = new SpecificX();
public string A { get => this.b.A; set => this.b.A = value; } // delegate the call
public string B { get; set; }
public string C { get => this.b.C; set => this.b.C = value; } // delegate the call
public string D { get; set; }
}
I created the following abstract class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract object Value { get; set; }
}
Now I want to derive two classes of the abstract class. I want to use an enum instead of the type object. My derived classes look like this:
First class:
public class InheritanceClass1:AbstractClass
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
Second class:
public class InheritanceClass2 : AbstractClass
{
public override string Name { get; set; }
public override SecondEnum Value { get; set; }
}
I'm getting an error showed in my code, that the type of the property Value isn't object. I tryed to use the new-keyword instead of override like this:
In my abstract class:
public object Value { get; set; }
In my derived class:
public new FirstEnum Value { get; set; }
But if I create a List<AbstractClass> I have the problem that I can't use it for example for Linq because I would retrieve the "wrong" property. It is just hided, but still there, so I have to override the property.
So how do I have to change my abstract class and my derived classes, that I can use different types in my derived classes?
You can use abstract class like this:
public abstract class AbstractClass<T>
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
And derived class will change like this:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
If you know that you will need only enums, you can add struct, IConvertible restriction to T:
public abstract class AbstractClass<T> where T : struct, IConvertible
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
Update based on comment:
Not the cleanest solution if you need List<AbstractClass>, but you can have additional class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract int GetValue ();
}
Which will then be inherited by AbstractClass<T>:
public abstract class AbstractClass<T> : AbstractClass where T : struct, IConvertible
{
public abstract T Value { get; set; }
}
And InheritancClass:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
public override int GetValue () => (int)Value;
}
And then you can use it in a list:
var list = new List<AbstractClass> { new InheritanceClass1 (), new InheritanceClass2 () };
In this way you can use List<AbstractClass> with GetValue method. If you are using only enums you can always recast it to enum value. Ofcorse, you would not know exactly which enum it is, but you can add additional field for that.
I have the following two classes:
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
}
So in other words I am wanting a type if interface that can have definitions or variables which all classes that implement it have to have, but they could add more if they required ?
The above example builds, even if i dono add the members from the abstract class.
edit
Forget what I've said before. These are attributes, not methods. For them to be accessible on derived classes, you make them protected or public. The difference is that public members are visible to the world, while protected ones are visible to the class and subclasses.
Any class derived from your LogItem may have other variables.
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
private void TestMethod(){
String test = payload;
}
}
check out this post for more information
Your MyLogItem class can reference any of the above members directly. They are accessible
You may declare an interface with those
public interface MyInterface {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
and your class
public class MyLogItem : MyInterface
{
String _payload;
public String payload { get{ return _payload; } set {_payload=value;} }
...
}
The abstract keyword can also be applied to methods, as described here.
Short version:
How can I best avoid using multiple type parameters? According to this it is a bad idea.
Long version:
I have 3 interfaces. I have multiple classes implementing these interfaces. It looks something like this:
public interface IMyInterface1 { }
public interface IMyInterface2 { }
public interface IMyInterface3 { }
public class MyClass1A : IMyInterface1 { public int Id { get; set; } }
public class MyClass1B : IMyInterface1 { }
public class MyClass1C : IMyInterface1 { }
public class MyClass2A : IMyInterface2 { }
public class MyClass2B : IMyInterface2 { }
public class MyClass2C : IMyInterface2 { }
public class MyClass3A : IMyInterface3 { }
public class MyClass3B : IMyInterface3 { }
public class MyClass3C : IMyInterface3 { }
Originally I had a base class and a class that derives from it with multiple type parameters like this:
public abstract class MyBaseClass<T, U, V>
where T : IMyInterface1
where U : IMyInterface2
where V : IMyInterface3
{
public T ConcreteMyInterface1 { get; set; }
public U ConcreteMyInterface2 { get; set; }
public V ConcreteMyInterface3 { get; set; }
public abstract T DoStuffWithInterface1();
}
public class MyClass : MyBaseClass<MyClass1A, MyClass2A, MyClass3A>
{
public override MyClass1A DoStuffWithInterface1()
{
var id = ConcreteMyInterface1.Id;
return ConcreteMyInterface1;
}
}
In an effort to remove the type parameters I refactored the code but it resulted in me having to cast everywhere like this:
public abstract class MyBaseClass
{
public IMyInterface1 ConcreteMyInterface1 { get; set; }
public IMyInterface2 ConcreteMyInterface2 { get; set; }
public IMyInterface3 ConcreteMyInterface3 { get; set; }
public abstract IMyInterface1 DoStuffWithInterface1();
}
public class MyClass : MyBaseClass
{
public MyClass()
{
ConcreteMyInterface1 = new MyClass1A();
ConcreteMyInterface2 = new MyClass2A();
ConcreteMyInterface3 = new MyClass3A();
}
public override IMyInterface1 DoStuffWithInterface1()
{
var id = ((MyClass1A)ConcreteMyInterface1).Id;
return ConcreteMyInterface1;
}
}
I was hoping for something more helpful than what Microsoft had to say in the above linked article:
To fix a violation of this rule, change the design to use no more than two type parameters.
When I use a generic interface, which is an overload of a normal interface I get an error the property of the normal interface is not implemented.
Example:
public interface IInterface1
{
string Bar1{ get; set; }
string Bar2{ get; set; }
}
public interface IInterface2
{
IInterface1 Foo{ get; }
}
public interface IInterface3<T>:IInterface2 where T:IInterface1
{
new T Foo { get; set; }
}
public class Class1<T> : IInterface3<T> where T : IInterface1
{
public T Foo { get; set; }
}
ERROR: 'Class1' does not implement interface member 'IInterface2.Foo'. 'Class1.Foo' cannot implement 'IInterface2.Foo' because it does not have the matching return type of 'IInterface1'.
But T is always of type IInterface1. What am I doing wrong?
Edit1:
If I remove the IInterface3, I cannot return T from my class
Edit2:
When I change Foo of Class1 to return IInterface1 instead of T, I'll still get an error
Edit3:
When I change IInterface3 and Class1 to return the same object in 2 ways it does work.
I only want Foo and Foo1 in Class1 combined.
(btw: removed the setter of IInterface2. I don't need it)
Solution:
The answers of fejesjoco and Rik got me thinking and helped me in this final solution:
public interface IInterface1
{
string Bar1 { get; set; }
string Bar2 { get; set; }
}
public interface IInterface2
{
IInterface1 Foo { get; }
}
public interface IInterface3<T>:IInterface2 where T:IInterface1
{
new T Foo { get; set; }
}
public class Class1<T> : IInterface3<T> where T : IInterface1
{
private T _foo;
T IInterface3<T>.Foo { get { return _foo; } set { _foo = value; } }
IInterface1 IInterface2.Foo { get { return _foo; } }
}
or
public class Class1<T> : IInterface3<T> where T : IInterface1
{
public T Foo { get; set; }
IInterface1 IInterface2.Foo { get { return Foo; } }
}
The prove of the pudding is in the tasting:
public class ImplemetationA : IInterface1
{
public string Bar1 { get; set; }
public string Bar2 { get; set; }
// some extra definitions here
}
public class ImplemetationB : IInterface1
{
public string Bar1 { get; set; }
public string Bar2 { get; set; }
// some extra definitions here
}
public class Problem : Class1<ImplemetationA>
{
public ImplemetationA Foo { get; set; }
}
public class ProblemSolved
{
public IInterface2 Method1()
{
var solvedProblem = new Problem();
solvedProblem.Foo = new ImplemetationA();
return solvedProblem;
}
public void Method2()
{
IInterface2 solvedProblem = Method1();
var result = solvedProblem.Foo;
}
}
But T is always of type IInterface1
Not exactly. T will be a type that implements IInterface1, but it will never be exactly IInterface1. Member signatures must match the interface specification exactly. You have to implement a property with the name Foo and type IInterface1. You can use explicit interface implementation and call into the other Foo, this way they will work the same way.
Edit: I think what you are looking for is this:
public interface IInterface1
{
string Bar1{ get; set; }
string Bar2{ get; set; }
}
public interface IInterface2<T> where T : IInterface1
{
T Foo{ get; set; }
}
public class Class1<T> : IInterface2<T> where T : IInterface1
{
public T Foo { get; set; }
}
Edit2
If you need to also have a non-generic interface, you can try this:
public interface IInterface1
{
string Bar1{ get; set; }
string Bar2{ get; set; }
}
public interface IInterface2
{
IInterface1 Foo{ get; }
}
public interface IInterface3<T>:IInterface2 where T:IInterface1
{
new T Foo { get; set; } // hide the non-generic IInterface2.Foo
}
public class Class1<T> : IInterface3<T> where T : IInterface1
{
public T Foo { get; set; }
IInterface1 IInterface2.Foo { get { return Foo; }} // explicitely implement IInterface2.Foo
}
This compiles, but I'm not 100% sure this also gives the desired behavior.
Original Answer
I was typing almost exactly what fejesjoco already answered. I'd just like to illustrate why this is a problem.
Consider a few additional classes:
public class ImplemetationA : IInterface1
{
string Bar1{ get; set; }
string Bar2{ get; set; }
// some extra definitions here
}
public class ImplemetationB : IInterface1
{
string Bar1{ get; set; }
string Bar2{ get; set; }
// some extra definitions here
}
public class Problem : Class1<ImplemetationA>
{
public ImplemetationA Foo {get; set;}
}
So the class Problem implements the interface as you defined it. The issue is that Problem still has to implement the non-generic interface IInterface2. According to your logic, this requirement is fulfilled by the already present property Foo in class Problem, because "T is always of type IInterface1". But what happens why we try to do this:
var myProblem = new Problem(); // remember, Problem : Class1<ImplemetationA>
var myImplB = new ImplementationB();
myProblem.Foo = myImplB;
Problem implements IInterface2, and since ImplementationB implements IInterface1, this should be allowed, but obviously, there's a type conflict here because there is no implicit conversion between ImplemetationB and ImplemetationA.