[Edited for additional clarity]
I have an abstract class where I've defined a property - let's call it 'BulkValueSet'. BulkValueSet is a class which holds a large number of numeric values.
public abstract class Parent
{
public BulkValueSet ValueSet {get;set;}
// additional properties and methods
}
BulkValueSet implements several different interfaces. Let's take two of them called ISpecificValueSetA and ISpecificValueSetB.
public class BulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
Now for the crux of the matter: I have two child classes (ChildA and ChildB) that inherit from the Parent class. I would like for these classes to inherit the BulkValueSet property from the Parent class but modify it via the interfaces defined. I've tried hiding the parent property by using the new keyword
public class ChildA : Parent
{
new public ISpecificValueSetA ValueSet {get;set;}
// additional stuff
}
public class ChildB : Parent
{
new public ISpecificValueSetB ValueSet {get;set;}
// additional stuff
}
the intent being that the property read from the child classes returns the filtered values as provided by the relevant interface. But this isn't really working - Visual studio shows both parent and child properties as being present and accessible and accessing the 'ValueSet' property using the dot operator seems to default to the property defined in the Parent class.
How can I go about this ?
Edit: Adding some additional context - I want to do this with multiple child classes - each with their own interface implementation of BulkValueSet.
what is wrong with it
public abstract class Parent
{
public IBulkValueSet ValueSet {get;set;}
// additional properties and methods
}
update, since the question was changed. Now ISpecificValueSet could be like this
public interface IBulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
public class BulkValueSet : IBulkValueSet
{
// lots of numbers !
}
but it doesn't make much sense to me to inherit a huge class in order to use a part of it.
This is the closest that I think I can get to your desired design:
public interface IParent
{
BulkValueSet ValueSet { get; set; }
}
public abstract class Parent : IParent
{
BulkValueSet IParent.ValueSet { get; set; }
}
public interface ISpecificValueSetA { }
public interface ISpecificValueSetB { }
public interface ISpecificValueSetC { }
public class BulkValueSet : ISpecificValueSetA, ISpecificValueSetB, ISpecificValueSetC { }
public class ChildA : Parent
{
public ISpecificValueSetA ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildB : Parent
{
public ISpecificValueSetB ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildC : Parent
{
public ISpecificValueSetC ValueSet { get => (this as IParent).ValueSet; }
}
Related
I have Bills and Receipts. Both types have a property called Lines, but Receipt.Lines is full of ReceiptLines and Bill.Lines is full of BillLines. I'd like them to both inherit from a class called Document with a property Lines that's full of DocumentLines so that I can occasionally pass them to functions that operate on Documents, but I don't want to have to myReceipt.Lines.Select(line => (ReceiptLine)line) each time I am specifically using a Bill or Receipt. Is there an elegant way to do this?
Note that the following attempt results in CS1503 Argument 1: cannot convert from 'Receipt' to 'Document<DocumentLine>'
void Main()
{
var something = new Receipt();
DoStuff(something);
}
public void DoStuff(Document<DocumentLine> document) { }
public abstract class DocumentLine { }
public class BillLine : DocumentLine { }
public class ReceiptLine : DocumentLine { }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { }
public class Receipt : Document<ReceiptLine> { }
Note that you cannot change a type when overriding, but you can make the line type a generic parameter.
public abstract class DocumentLine { ... }
public class BillLine : DocumentLine { ... }
public class ReceiptLine : DocumentLine { ... }
public abstract class Document<TDocLine> where TDocLine : DocumentLine
{
public List<TDocLine> Lines { get; set; }
}
public class Bill : Document<BillLine> { ... }
public class Receipt : Document<ReceiptLine> { ... }
Deriving the line types from a common base has advantages. 1) you can reuse stuff common to both line types. 2) You can limit the actual types of TDocLine. This safer as it disallows you to specify an inappropriate type and it allows you to access the common members declared in DocumentLine from other methods in the Document<TDocLine> class.
You could use a generic type to define the List item type, like so:
interface DocumentLine { }
class BillLine : DocumentLine { }
class ReceiptLine : DocumentLine { }
class Document<T> where T : DocumentLine
{
public List<T> Lines { get; set; }
}
class Bill : Document<BillLine> { }
class Receipt : Document<ReceiptLine> { }
Edit: What the new implied question is referring to is called 'Generic Covariance'. In C# generic covariance is limited to interface and delegate types [see out keyword (generic modifier)].
Instead, to get the behavior you want, you'll have to carry the generic variable as generic with conditions, rather than a fixed covariant type.
public void DoStuff<T>(Document<T> document) where T : DocumentLine { }
I have seen this kind of definition in a library I'm using. I got crazy about the where TObjectType: CSObject. It is obvious that It seems I can use the same time in the constraint because it works and compiles but what does this really mean?
public class CSList<TObjectType>: CSList, IList<TObjectType>, IList
where TObjectType: CSObject<TObjectType>
It means that the TObjectType here must inherit from CSList<TObjectType>.
Usually you use this construct to get typed methods and properties on the base class that adjust to the actual derived classes you intend to use.
To declare such a derived class:
public class SomeDerivedClass : CSList<SomeDerivedClass>
Example:
public class Base<T>
{
public T[] Values { get; set; }
}
public TestCollection : Base<TestCollection>
{
// here, Values inherited from Base will be:
// public TestCollection[] Values { get; set; }
}
public OtherCollection : Base<OtherCollection>
{
// here, Values inherited from Base will be:
// public OtherCollection[] Values { get; set; }
}
using C# I have a class which contains among other meta information the root node of a directed graph. Let's call this the Container-Class. This container can appear in two different modes, Editor-Mode and Configurator-Mode. Depending on the mode, the root-node is of a different type NodeEdit or NodeConfig, both inheriting from the same subclass.
public abstract class NodeBase
{
string Name { get; set; }
...
}
public class NodeEdit : NodeBase ...
public class NodeConfig : NodeBase ...
For the container, I also create a base class and inherit from it:
public abstract class ContainerBase
{
NodeBase Root { get; set; }
...
}
When creating the classes for Editor- and Configuratorcontainer by inheriting from ContainerBase, I want to become the type of the Root - property the specific (inherited from NodeBase) type like:
public class ContainerEditor : ContainerBase
{
NodeEditor Root { get; set; }
...
}
But I cannot change the type of a property defined in ContainerBase. Is there a way to solve this problem? I can use the BaseNode-type, and add an element of NodeEditor like
ContainerEditorInstance.Root = new NodeEditor();
because the type NodeEditor is inherited from type BaseEditor, but in the Container-Editor class, I want to explicitly only allow the type of the Root-property to be NodeEditor.
I could check this in the setter and reject all nodes but those of type NodeEditor, but I'd like to have the property be of the specific type, so I can detect wrong assignments at compile-time.
Thanks in advance,
Frank
Use generics:
public abstract class ContainerBase<T> where T:NodeBase
{
T Root { get; set; }
...
}
public class ContainerEditor : ContainerBase<NodeEditor>
{
...
}
You can redeclare it:
public class ContainerEditor : ContainerBase
{
public NodeEditor Root {
get { return (NodeEditor)base.Root; }
set { base.Root = value; }
}
...
}
You can make the container base generic:
public abstract class ContainerBase<TRoot> where TRoot : NodeBase
{
TRoot Root { get; set; }
...
}
In the derived class you specify the type:
public class ContainerEditor : ContainerBase<NodeEditor>
{
...
}
I suppose a good solution here will be Generics. So you'd write something like this:
public class ContainerEditor<T>:ContainerBase
{
T Root {get;set;}
}
I want to create a hierarchical structure that will closely follow the following structure:
(1) INodeBase - contains a Children property that is a Collection of itself (INodeBase)
(2) INodeFolder - derives from INodeBase.
(3) NodeFolder - implements INodeFolder. The implementation of the Children property should allow it to contain items of both the INodeFolder type and INodeItem type.
(4) INodeItem - derives from INodeBase.
(5) NodeItem - implements INodeItem. The implementation of the Children property should allow it to contain items of the NodeResult type.
(6) INodeResult - derives from INodeBase.
(7) NodeResult - implements INodeResult - I don't need/want a children property in this class, but, I am willing to have an empty collection hang off of the class if the overall hierarchy can be structured properly.
Essentially, I want one base type for node - and the assumption should be that a node can contain other nodes. I am thinking that generics is the way to go - but - the problem is that if I query off of the overall hierarchical collection, or rather, if I filter on it, when I am recursively going through each child's children collection (i.e. flattening my collection), I want to know what is what - i.e., if I am in the Children collection of a folder, I want to know when I hit a FolderNode and when I hit an ItemNode, and then when I recurse through the Children property of an ItemNode, I want to know that I am just dealing with the NodeResult type.
So, what is the best approach for the above?
Chris
I think the below code all follows the rules you wanted, particularly with all node implementing INodeBase and with the bonus that NodeResult doesn't have a Children collection.
Here are the interfaces required:
public interface INodeBase
{
}
public interface INodeContainer : INodeBase
{
}
public interface INodeContainer<C> : INodeContainer
where C : INodeBase
{
IList<C> Children { get; }
}
public interface INodeFolder : INodeContainer<INodeContainer>
{
}
public interface INodeItem : INodeContainer<INodeResult>
{
}
public interface INodeResult : INodeBase
{
}
I have added a couple of INodeContainer interfaces - one non-generic & the other generic.
Here are the class definitions:
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeContainer : NodeBase, INodeContainer
{
}
public abstract class NodeContainer<C> : NodeContainer, INodeContainer<C>
where C : INodeBase
{
public NodeContainer() { this.Children = new List<C>(); }
public IList<C> Children { get; private set; }
}
public class NodeFolder : NodeContainer<INodeContainer>, INodeFolder
{
}
public class NodeItem : NodeContainer<INodeResult>, INodeItem
{
}
public class NodeResult : INodeResult
{
}
Now you can use the code like this:
var nf = new NodeFolder();
nf.Children.Add(new NodeFolder()); // Add `INodeFolder`
var ni = new NodeItem();
nf.Children.Add(ni); // or add `INodeFolder`, but nothing else.
var nr = new NodeResult();
ni.Children.Add(nr); // Only add `INodeResult`.
// nr does not have "Children" collection.
You can restrict INodeContainer<C> on the concrete types rather than the interfaces if you wish. It depends on if you want to reference the objects by interface or by concrete class.
Let me know if this works for you.
Altought, is not the main answer, why don't you design your object hierarchy, directly with classes and objects, instead of interfaces. Later you may turn it into an interface hierarchy.
enum NodeTypes { Unknown, Folder, File };
public abstract class CNodeBase {
protected List<CNodeBase> FItems;
public List<CNodeBase> Items();
public virtual NodeTypes NodeType() {
return NodeTypes.Unknown;
}
}
public class CNodeFolder: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.Folder;
}
}
public class CNodeFile: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.File;
}
}
public class CDemo {
void main () {
// root node is ALWAYS A folder
CNodeFolder RootNode = new CNodeFolder("\\");
CNodeBase AnyNode = null;
AnyNode = new CNodeFolder("c:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFolder("d:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFile("readme.txt");
RootNode.Add(AnyNode);
}
}
Superclasses (both abstract or concrete) work very similar to interfaces, but have the advantage that you can instantiate objects from them, see the code working.
Its seems to me, that you are trying to do something very conceptual. Maybe if you step back a little, going to classes that can be instantiated, you may get a more practical view of your idea.
Interfaces are a very good feature, yet, its difficult to understand, at first. Sometimes, is a good idea to "take one step back, to go five steps forward".
Why do you need to have folders and items implement the same interface?
It seems to me that a simpler structure like this would work better...
public class Folder
{
public List<Folder> Folders { get; }
public List<Item> Items { get; }
}
public class Item
{
public List<Result> Results { get; }
}
public class Result
{
}
I have an abstract class BaseItem declared like this:
public abstract class BaseItem
{
public BaseItem Parent { get; protected set; }
public List<BaseItem> Children = new List<BaseItem>();
public abstract string Function1();
}
Basically, i'm trying to implement a design where each Item has a parent that will be of one specific type and children that will be of a different type.
For example, ItemA would have children all of ItemB type. Then ItemB would have a parent of ItemA type and children all of ItemC type. ItemC would have parent of ItemB and children of ItemD type.
I thought it would be neater to do this using generics to avoid unnecessary casts since i know what type the parent and children will be for each of my inherited classes. So i came up with something like this:
public abstract class AbstractBase
{
public abstract string Function1();
}
public abstract class BaseItem<T1, T2> : AbstractBase
where T1 : AbstractBase
where T2 : AbstractBase
{
public T1 Parent { get; protected set; }
public List<T2> Children = new List<T2>();
}
public class ItemA : BaseItem<ItemA, ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : BaseItem<ItemC, ItemD>
{
}
So two things.
1. Is this a good design? Is there a simpler/better way of doing this? I don't really like using a second abstract base class just to be able to use generics.
2. If i do keep this, what's the best way of handling the ends? (i.e ItemA does not have a parent in my actual problem domain, but it needs a parent to compile. ItemD does not have children, but i need to give it something)
If I understand you right, you are saying that ItemA never has a parent and ItemD never has any children, right? To be honest, I would probably just declare the separate classes with their own parent/children properties of the right type:
public abstract class AbstractBase
{
public abstract string Function1();
}
public class ItemA : AbstractBase
{
public List<ItemB> Children = new List<ItemB>();
}
public class ItemB : AbstractBase
{
public ItemA Parent { get; protected set; }
public List<ItemC> Children = new List<ItemC>();
}
public class ItemC : AbstractBase
{
public ItemB Parent { get; protected set; }
public List<ItemD> Children = new List<ItemD>();
}
public class ItemD : AbstractBase
{
public ItemC Parent { get; protected set; }
}
The only thing you are repeating here is the Parent and Children property/field. All the other common functionality you can implement in the AbstractBase. (Unless, of course, that functionality needs access to the parents/children — but then you’re back to square one even in your solution.)
I would do it like this:
public interface IChildOf<T> {
T Parent { get; set; }
}
public interface IParent<T> {
List<T> Children { get; set; }
}
//This class handles all of the cases that have both parent and children
public abstract class BaseItem<T1, T2> : IParent<T1>, IChildOf<T2>
{
public List<T1> Children { get; set; }
public T2 Parent { get; set; }
}
//This class handles the top level parent
public class ItemA : IParent<ItemB>
{
public List<ItemB> Children { get; set; }
}
public class ItemB : BaseItem<ItemC, ItemA>
{
}
public class ItemC : BaseItem<ItemD, ItemB>
{
}
//.... as many intermediates as you like.
//This class handles the bottom level items with no children
public class ItemD : IChildOf<ItemC>
{
public ItemC Parent { get; set; }
}
You might use two generic interfaces, ChildOf<T> and IList<T>. This will let you handle the end cases. Unfortunately since .NET doesn't have multiple inheritance, you won't be able to share the implementation.
Alternatively you could use the abstract class and a marker type (System.Void would be ideal, but I don't think it would compile) for the end cases, and check for it from the Parent/Children properties and throw an exception.
It doesn't seem like too bad an idea, although to be honest I'd be tempted to keep the original solution and put up with the casting as it does add a fair bit of complexity for not that much benefit. (Although I must admit I try to replace casting with generics whenever I can).
If you did want to keep it, a couple of suggestions:
have AbstractBase as an interface
do something different for the ends (e.g. two extra BaseItems which take a parent and a child generic type).
Obviously, this second point only adds to the complexity, which is another reason I'm not sure it's worthwhile.
I don't see a problem with doing things this way, since you appear to have a specific heirarchy that requires top-level items to be of type ItemA, 2nd-level items to be of type ItemB, etc.
To address the root and leaf nodes, I'd probably define separate classes that also derive from AbstractBase:
public abstract class RootItem<T2> : AbstractBase
where T2 : AbstractBase
{
public List<T2> Children = new List<T2>();
}
public abstract class LeafItem<T1> : AbstractBase
where T1 : AbstractBase
{
public T1 Parent { get; protected set; }
}
public class ItemA : RootItem<ItemB>
{
}
public class ItemB : BaseItem<ItemA, ItemC>
{
}
public class ItemC : BaseItem<ItemB, ItemD>
{
}
public class ItemD : LeafItem<ItemC>
{
}