I have below simple object model where Manager class consist List Of Child objects and Child object must have reference to it's parent object:
public class ManagerBase<T1> where T1 : ChildBase<???>
{
public ManagerBase()
{
ChildObjects = new List<T1>();
}
public List<T1> ChildObjects { get; set; }
}
public class ChildBase<T1> where T1 : ManagerBase<???>
{
public ChildBase(T1 parentMgr)
{
ParentMgr = parentMgr;
ParentMgr.ChildObjects.Add(this);
}
public T1 ParentMgr { get; set; }
}
Above are BASE classes. Now, below are inherited sample Manager and Child classes. I don't know how to make below classes to compile as above BASE classes are not valid yet. Could you pls help? Thanks.
public class CatalogManager : ManagerBase<Catalog>
{
}
public class Catalog : ChildBase<CatalogManager>
{
}
To provide more clear idea: I have BASE Manager class, BASE Child Object class. There are different type of inherited Managers (CatalogManager, DocumentManager etc.) and different type of Child Objects (Catalog, Document etc). Now, each Manager must consist of List not List. F.e: CatalogManager with List, DocumentManager with List. At the same time, each child object must have reference to it's Manager. In other words, I need strong typing instead of using Base classes. Hope it clear. Thanks for your time.
You can achieve that by creating non-generic base classes for the generic base classes. Answer updated to avoid type casting; to do so, ChildObjects property had to be IEnumerable<T> because it's type parameter is covariant, while classes, IList<T>, and ICollection<T> are contravariant.
public abstract class ManagerBase
{
protected ManagerBase()
{
innerChildObjectList = new List<ChildBase>();
}
private IList innerChildObjectList;
public IEnumerable<ChildBase> ChildObjects
{
get
{
foreach (ChildBase child in innerChildObjectList.OfType<ChildBase>())
yield return child;
}
}
public void AddChild<T>(T child) where T : ChildBase
{
innerChildObjectList.Add(child);
}
public void RemoveChild<T>(T child) where T : ChildBase
{
innerChildObjectList.Remove(child);
}
public bool ContainsChild<T>(T child) where T : ChildBase
{
return innerChildObjectList.Contains(child);
}
//Add 'Insert', 'RemoveAt' methods if needed.
}
public abstract class Manager<T>
: ManagerBase
where T : ChildBase
{
public new IEnumerable<T> ChildObjects
{
get { return base.ChildObjects.OfType<T>(); }
}
}
public abstract class ChildBase
{
protected ChildBase(ManagerBase mgr)
{
ParentMgr = mgr;
}
private ManagerBase parentMgr;
public ManagerBase ParentMgr
{
get { return parentMgr; }
set
{
if (parentMgr != null && parentMgr.ContainsChild(this))
parentMgr.RemoveChild(this);
parentMgr = value;
parentMgr.AddChild(this);
}
}
}
public abstract class Child<T>
: ChildBase
where T : ManagerBase
{
protected Child(T mgr) : base (mgr)
{
}
public new T ParentMgr
{
get { return base.ParentMgr as T; }
set { base.ParentMgr = value; }
}
}
Now this will be okay:
public class CatalogManager : Manager<Catalog>
{
}
public class Catalog : Child<CatalogManager>
{
public Catalog(CatalogManager parentMgr) : base(parentMgr)
{
}
}
Related
I had a class which represents a prefix search tree:
public class PrefixTree<TData>
{
private PrefixTree<TData>[] _children;
private void SomeMethod()
{
_children = new PrefixTree<TData>[10];
}
}
Then I created a derived class with additional features for its nodes:
public class NewPrefixTree<TData> : PrefixTree<TData>
The problem is that in SomeMethod() of derived class we still create instances of base class and it doesn't fit the meaning.
I refactored the base class to this:
public abstract class PrefixTree<TData, TNode>
where TNode : PrefixTree<TData, TNode>, new()
{
private TNode[] _children;
private void SomeMethod()
{
_children = new TNode[10];
}
}
Despite the base class has complete functionality itself, I had to make it abstract because I can't write new DigitalPrefixTree<TData, DigitalPrefixTree<int, ...>>() .
But now I can use it this way and it works perfectly:
public class NewPrefixTree<TData> : PrefixTree<TData, NewPrefixTree<TData>> {} // for derived class
//or
public class PrefixTree<TData> : PrefixTree<TData, PrefixTree<TData>> {} // to use the base functionality
I've never done this before and I wonder if it's a good idea to declare a class with generic parameter of the same generic class type. Or I need to make some tricks with co/contra-variance of generic interfaces (but it probably doesn't work as I use the class type as method’s parameters type and as return type as well)?
Try this:
public interface INode<out TData>
{
TData Data { get; }
IEnumerable<INode<TData>> Children { get; }
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public interface ITree<out TData>
{
IEnumerable<INode<TData>> Children { get; }
IEnumerable<TRequiredData> GetNestedData<TRequiredData>();
}
public class Node<TData> : INode<TData>
{
public TData Data { get; }
public IEnumerable<INode<TData>> Children { get; }
public Node(TData data, IEnumerable<INode<TData>>? children = null)
{
Data = data;
Children = children ?? Enumerable.Empty<INode<TData>>();
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
if (Data is TRequiredData requiredData)
result.Add(requiredData);
foreach (var child in Children)
result.AddRange(child.GetNestedData<TRequiredData>());
return result;
}
}
public class Tree<TData> : ITree<TData>
{
public IEnumerable<INode<TData>> Children { get; }
public Tree(IEnumerable<INode<TData>> children)
{
Children = children;
}
public IEnumerable<TRequiredData> GetNestedData<TRequiredData>()
{
List<TRequiredData> result = new();
foreach (var node in Children)
result.AddRange(node.GetNestedData<TRequiredData>());
return result;
}
}
And here is example of usage:
record SomeRecord();
class SomeClass {}
static void Main(string[] args)
{
var nodeWithNested = new Node<SomeClass>(
data: new SomeClass(),
children: new List<INode<SomeClass>>()
{
new Node<SomeClass>(new SomeClass()),
new Node<SomeClass>(new SomeClass())
});
var nodes = new List<INode<object>>()
{
new Node<SomeClass>(new SomeClass()),
nodeWithNested,
new Node<SomeRecord>(new SomeRecord()),
};
var tree = new Tree<object>(nodes);
var someClasses = tree.GetNestedData<SomeClass>(); // 4 items
var someRecords = tree.GetNestedData<SomeRecord>(); // 1 item
}
This approach based on out generic modifier.
The only restriction is that you can not use structs (int, bool and ect.) as they don't have common object to cast to.
Hope this will be useful.
I have a chain of responsibility that applies filters to a collection. I am trying to make a factory to build that chain of responsibility from a configuration. My concrete types for the chain arent generic but their abstraction are, and the genericity makes me struggle to put them in a collection for a mapping between config and correct chain node implementation.
Here is the implementation of the chain :
public interface IFilter<T> where T : IFilterable
{
IFilter<T> SetNext(IFilter<T> next);
IEnumerable<T> Filter(IEnumerable<T> data);
}
public class BaseFilter<T> : IFilter<T> where T : IFilterable
{
protected IFilter<T> Next { get; set; }
public IFilter<T> SetNext(IFilter<T> next)
{
Next = next;
return Next;
}
public virtual IEnumerable<T> Filter(IEnumerable<T> data)
{
return Next == null ? data : Next.Filter(data);
}
}
Here is an example of concrete implementation of the nodes of the chain :
public interface IFilterable {}
public interface ICanFly: IFilterable
{
bool CanFly { get; }
}
public interface ITransport : IFilterable
{
int Passengers { get; }
}
public class Duck : ICanFly
{
public bool CanFly => true;
}
public class Plane : ICanFly, ITransport
{
public bool CanFly => true;
public int Passengers => 5;
}
public class FlyerFilter : BaseFilter<ICanFly>
{
public override IEnumerable<ICanFly> Filter(IEnumerable<ICanFly> data)
{
return base.Filter(data.Where(x => x.CanFly));
}
}
public class SmallTransportFilter : BaseFilter<ITransport>
{
public override IEnumerable<ITransport> Filter(IEnumerable<ITransport> data)
{
return base.Filter(data.Where(x => x.Passengers < 8));
}
}
My problems start when I want to make a factory that map the configuration to my concrete types (FlyerFilter and SmallTransportFilter in my example)
public interface IFilterChainBuilder<T> where T : IFilterable
{
IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam);
}
public class FilterChainBuilder<T> : IFilterChainBuilder<T> where T : IFilterable
{
private readonly Dictionary<string, IFilter<T>> _paramToFiltersMap;
public FilterChainBuilder()
{
_paramToFiltersMap = new Dictionary<string, IFilter<T>>(StringComparer.OrdinalIgnoreCase)
{
{"Flyers", new FlyerFilter()}, // Compile error, cannot convert from FlyerFilter to IFilter<T>
{"SmallTransport", new SmallTransportFilter()} // Compile error, cannot convert from SmallTransportFilter to IFilter<T>
};
}
public IFilter<T> GenerateFilterResponsabilityChain(IEnumerable<string> filtersParam)
{
IFilter<T> filterResponsabilityChain = null;
foreach (var parameter in filtersParam)
if (_paramToFiltersMap.TryGetValue(parameter, out var filter))
{
if (filterResponsabilityChain == null)
filterResponsabilityChain = filter;
else
filterResponsabilityChain.SetNext(filter);
}
else
{
throw new ArgumentException(
$"config parameter {parameter} has no associated IFilter");
}
return filterResponsabilityChain ?? new BaseFilter<T>();
}
}
I can understand why it doesnt compile. Since FlyerFilter is a BaseFilter<ICanFly> (so a IFilter<ICanFly>), it would be bad if I declared a new FilterChainBuilder<PlaceholderType>. And actually since SmallTransportFilter inherit from a different T type, the only possible IFilterable implementation would have to implement both ITransport and ICanFly.
I tried to remove the generic T type entirely but the consummer of this chain of responsability relies on that IEnumerable<T> Filter(IEnumerable<T> data) signature and wants an enumeration of concrete types rather than IFilterable.
I am not sure how could I fix this problem, I am currently stuck here.
Pavel is correct - Your definition of IFilter makes the type parameter T invariant. Putting covariance/controvariance/invariance aside, the design itself is questionable. For example, FlyFilter works only against ICanFly instances, but there is no code filters the input down to ICanFly elements only - shouldn't that be the responsibility of FlyFilter as well? I would personally suggest you use type info in your filters directly, maybe something like below:
public interface IFilterable { }
public class CanFly : IFilterable { }
public class Duck : CanFly { }
public abstract class Transportation : CanFly
{
public abstract int Passengers { get; }
}
public class Plane : Transportation
{
public override int Passengers => 5;
}
public class FlyerFilter : BaseFilter<IFilterable>
{
public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
{
return base.Filter(data.Where(x => x is CanFly));
}
}
public class SmallTransportFilter : BaseFilter<IFilterable>
{
public override IEnumerable<IFilterable> Filter(IEnumerable<IFilterable> data)
{
return base.Filter(data.Where(x => x is Transportation t && t.Passengers < 8));
}
}
I have the following classes, and when I call CreateQuerySettings on the BaseScriptConfigurationList, it returns the new QuerySettings from ConfigurationList, rather than the HierarchicalQuerySettings value in BaseScriptConfigurationList:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
_BaseScriptPageListWatcher = new ConfigurationList<BaseScriptPageConfiguration, BaseScriptPageConfiguration.Property>.
ConfigurationWatcher(null);
_ConfigurationWatcher.ChildWatchers.Add(_BaseScriptPageListWatcher);
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
Edit: I make the call from another class where TConfigurationObjectList is BaseScriptConfigurationList. I've added the constructor to the code above so you can see what it's doing. Please note that EditableConfigurationList inherits from ConfigurationList.
TConfigurationObjectList cl = (TConfigurationObjectList)typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var querySettings = cl.CreateQuerySettings();
When I make this call, it goes into the ConfigurationList.CreateQuerySettings method.
How can I hide the CreateQuerySettings method, so that when I call it from the BaseScriptConfigurationList class, I get a HierarchicalQuerySettings object?
The new modifier can be beasty. Note that you are hiding and not overriding in your example. You are not showing that part of the code, but I assume you have this situation:
class Base
{
public static void BaseMethod() { Console.WriteLine("BASE!"); }
}
class Derived : Base
{
// Hides Base.BaseMethod()
new public static void BaseMethod() { Console.WriteLine("DERIVED!"); }
}
Base a = new Base();
a.BaseMethod(); // -> "BASE!"
Base b = new Derived();
b.BaseMethod(); // -> "BASE!"
Derived b = new Derived();
b.BaseMethod(); // -> "DERIVED!"
In BaseScriptConfigurationList.CreateQuerySettings()
you're return type is QuerySettings<T,T> so you will always get that type as a return value, but you are returning a HierarchicalQuerySettings. You can one, change the return type of CreateQuerySettings() to HierarchicalQuerySettings or two, cast the object to its child type "HierarchicalQuerySettings". If you really want to hide it, you can do this:
public class newclass : BaseScriptConfigurationList
{
public new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return (HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>)base.CreateQuerySettings();
}
}
But that doesn't really seem efficient and i advise against it. Like i said, i maybe missing some other requirement, but based on the info that you gave..
Basically, what I'm seeing (and making assumptions) that TConfigurationObjectList Inhertis from ConfigurationList somewhere along the lines, so on and so forth, all the way up to EditableConfigurationList. since you are dynamically creating an instance of the class TConfigurationObjectList, and calling the method from that point, you will be calling the base ConfigurationList member CreateQuerySettings. You do not have access to the new CreateQuerySettings. If you are creating the class BaseScriptConfigurationList instance at this point, cast the object ((BaseScriptConfigurationList)cl).CreateQuerySettings(). That being said. if you do not know what you have at runtime:
var obj = typeof(TConfigurationObjectList).GetConstructor(new Type[] { typeof(ConfigurationManager) }).Invoke(new object[] { Manager.ConfigurationManager });
var cl = (obj as BaseScriptConfigurationList) ?? (TConfigurationObjectList)obj;
// or do something else
var querySettings = cl.CreateQuerySettings();
Note i am assuming your architecture is roughly set up like this:
public abstract class ConfigurationList<TConfigurationObject, TPropertyEnum>
{
public QuerySettings<TConfigurationObject, TPropertyEnum> CreateQuerySettings()
{
return new QuerySettings<TConfigurationObject, TPropertyEnum>();
}
}
public class TConfigurationObjectList : ConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class EditableConfigurationList<T, T1> : TConfigurationObjectList
{
protected EditableConfigurationList(ConfigurationManager configurationManager, object baseScript)
{
throw new NotImplementedException();
}
}
public class BaseScriptConfigurationList : EditableConfigurationList<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
public BaseScriptConfigurationList(ConfigurationManager configurationManager)
: base(configurationManager, InternalAdminObjectType.BaseScript)
{
}
public new QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property> CreateQuerySettings()
{
return new HierarchicalQuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property, BaseScriptQueryChildrenSettings>();
}
}
public class QuerySettings<T, T1>
{
}
public class HierarchicalQuerySettings<T, T1, T2> : QuerySettings<BaseScriptConfiguration, BaseScriptConfiguration.Property>
{
}
public class BaseScriptQueryChildrenSettings
{
}
public class BaseScriptPageConfiguration
{
public class Property
{
}
}
public class InternalAdminObjectType
{
public static object BaseScript { get; set; }
}
public class ConfigurationManager
{
}
public class BaseScriptConfiguration
{
public class Property
{
}
}
Create a base interface for the ConfigurationList class (say IConfigurationList) and use this interface as the data type for the variable cl instead of TConfigurationList.
I want to have a base class:
public class Base
{
public static T Instance
{
get
{
// do something to return new instance of inherit class from itself
}
}
}
Class1:
public class Class1 : Base
{
// method and properties here
public string Func1()
{
return 'class1';
}
}
Class2:
public class Class2 : Base
{
// method and properties here
public string Func1()
{
return 'class2';
}
}
I want it so that we can use Class1 or Class2 like this
public class Main
{
var a = Base<Class1>.Instance.Func1(); // return 'class1'
var b = Base<Class2>.Instance.Func1(); // return 'class2'
}
Please help me to do this.
This is not called dynamic but polymorphic. In this case achieved with generics. Your only remaining problem is calling the constructor, which becomes possible when you put a Type-constraint on <T>.
public class Base<T> where T : new()
{
public static T Instance
{
get
{
// do something to return new instance of inherit class from itself
return new T();
}
}
}
and then:
public class Class1 : Base<Class1> { ... }
public class Class2 : Base<Class2> { ... }
But note that a simpler solution could be achieved with virtual+override methods or with an interface.
Alternative suggestion with some tighter type constraints:
namespace My.Test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Base<Class1>.Instance.Func1());
Console.WriteLine(Base<Class2>.Instance.Func1());
}
}
public abstract class Base
{
public abstract string Func1();
}
public sealed class Base<T> where T : Base, new()
{
public static T Instance
{
get { return new T(); }
}
}
public class Class1 : Base
{
public override string Func1() { return "class 1"; }
}
public class Class2 : Base
{
public override string Func1() { return "class 2"; }
}
}
OK, so here is the situation. I've got a FlexCollection<T> class, which purpose is to hold a list of some specialization of FlexItem, therefore:
public class FlexCollection<T> where T : FlexItem, new()
{
public void Add(T item) { ... }
...
}
FlexItem is not generic class itself. What I wanted to achieve is ability to hold in FlexItem's field a reference to the collection that contains the object. Unfortunately in C# it is not possible to hold reference to "any" specialization of template class (as in Java). At first I tried to use non-generic interface IFlexCollection but it actually forced me to implement each method twice, i.e.:
public class FlexCollection<T> : IFlexCollection where T : FlexItem, new()
{
public void Add(T item) { ... } // to use in generic calls
public void Add(object item) { ... } // to use for calls from within FlexItem
...
}
Then I had found out that I could make FlexItem a generic class itself! Then a specialization can hold a reference to collection of objects of this specialization (which is quite logical). Therefore:
public class FlexItem<T> where T : FlexItem<T>, new()
{
public FlexCollection<T> ReferenceToParentCollection;
...
}
public class FlexCollection<T> where T : FlexItem<T>, new()
{
public void Add(T item) { ... }
...
}
Now i can declare some FlexItem<T> specialization and corresponding collection:
public class BasicItem : FlexItem<BasicItem> { public int A; }
public class BasicCollection : FlexCollection<BasicItem> { };
The problem arises when I try to extend those classes to hold additional fields. I.e. I wanted an ExtendedItem class which holds field B in addition to field A:
public class ExtendedItem : BasicItem { public int B; }
public class ExtendedCollection : FlexCollection<ExtendedItem> { };
And the thing is that ExtendedItem is a subclass of FlexItem<BasicItem> and not FlexItem<ExtendedItem>. Therefore is is impossible to declare ExtendedCollection as above. This causes a compilation error:
The type 'Demo.ExtendedItem' must be convertible to
'Demo.FlexItem<Demo.ExtendedItem>' in order to use it as parameter 'T'
in the generic type or method 'Demo.BasicCollection<T>'
Is there any way to avoid such type collision?
OK, i've decided to give C# events a try. This way I actually do not need FlexItem to hold a reference to owning FlexCollection. I simply raise an event i.e. "IAmBeingRemoved" and FlexCollection's code if performing corresponding actions. Code logic is even better encapsulated then. I just hope I will not run into any performance issues or other generic-based suprises. :-) I am posting it so that maybe somebody finds it a good solution for their own problem.
There are 2 ways you can resolve this:
You can use the base Polymorphic Collection and not inherit the base class collection:
class Program
{
static void Main(string[] args)
{
BasicCollection extendedCollection = new BasicCollection();
extendedCollection.Add(new ExtendedItem { A = 1, B = 2});
extendedCollection.Add(new BasicItem { A = 3 });
extendedCollection.Add(new ExtendedItem { A = 4, B = 5});
foreach (BasicItem item in extendedCollection)
{
switch(item.GetType().Name)
{
case "BasicItem":
Console.Out.WriteLine(string.Format("Found BasicItem: A={0}", item.A));
break;
case "ExtendedItem":
ExtendedItem extendedItem = item as ExtendedItem;
Console.Out.WriteLine(string.Format("Found ExtendedItem: A={0} B={1}", extendedItem.A, extendedItem.B));
break;
}
}
}
}
public class FlexItem<T> where T : FlexItem<T>, new()
{
public FlexCollection<BasicItem> ReferenceToParentCollection;
}
public class FlexCollection<T> where T : FlexItem<T>, new()
{
public void Add(T item) { }
}
public class BasicItem : FlexItem<BasicItem> { public int A; }
public class ExtendedItem : BasicItem { public int B; }
public class BasicCollection : FlexCollection<BasicItem>
{
Collection<BasicItem> items = new Collection<BasicItem>();
public void Add(BasicItem item)
{
item.ReferenceToParentCollection = this;
items.Add(item);
}
public void Remove(BasicItem item)
{
item.ReferenceToParentCollection = null;
items.Remove(item);
}
public IEnumerator GetEnumerator()
{
return items.GetEnumerator();
}
}
Or you can box the collection class reference and unbox it when you need it since you know the type of the child object?
class Program
{
static void Main(string[] args)
{
ExtendedCollection extendedCollection = new ExtendedCollection();
extendedCollection.Add(new ExtendedItem { A = 1, B = 2, ReferenceToParentCollection = extendedCollection });
extendedCollection.Add(new ExtendedItem { A = 3, B = 3, ReferenceToParentCollection = extendedCollection });
foreach (ExtendedItem item in extendedCollection)
{
(item.ReferenceToParentCollection as ExtendedCollection) ...
}
}
}
public class FlexItem<T> where T : FlexItem<T>, new()
{
public object ReferenceToParentCollection;
}
public class FlexCollection<T> where T : FlexItem<T>, new()
{
public void Add(T item) { }
}
public class BasicItem : FlexItem<BasicItem> { public int A; }
public class BasicCollection : FlexCollection<BasicItem> { };
public class ExtendedItem : BasicItem { public int B; }
public class ExtendedCollection : FlexCollection<ExtendedItem> { };
Not sure what is the purpose (usage) of your code, but it seems to me that you are trying to base something on a generics solution and later on 'get rid of' the generic data about some types - this is not possible in C#.
If you choose to pursue a generics approach you should always keep the info of the base of the generic types:
public class FlexItem<T> where T : FlexItem<T>, new()
{
public FlexCollection<T> ReferenceToParentCollection;
}
public class FlexCollection<T> where T : FlexItem<T>, new()
{
public void Add(T item)
{
}
}
public class BasicItem<T> : FlexItem<BasicItem<T>>
{
public int A;
}
public class BasicCollection<T> : FlexCollection<BasicItem<T>>
{
}
public class ExtendedItem<T> : BasicItem<T>
{
public int B;
}
public class ExtendedCollection<T> : FlexCollection<T> where T: FlexItem<T>, new()
{
}