Having trouble with inherited classes, constructors with generics - c#

I've got a semi-complex inheritance structure that I'm having difficulty with on overriding a constructor on a base class. The following code can show the error:
public abstract class MyBaseObject
{
public MyBaseObject(MyBaseCollection<MyBaseObject> parent)
{
this.Parent = parent;
}
public MyBaseCollection<MyBaseObject> Parent { get; set; }
}
public abstract class MyBaseCollection<T>
where T : MyBaseObject
{ }
public class MyRealObject : MyBaseObject
{
public MyRealObject(MyRealCollection parent)
: base(parent)
{ }
public new MyRealCollection Parent { get { return (MyRealCollection)base.Parent; } }
}
public class MyRealCollection : MyBaseCollection<MyRealObject>
{ }
So, specifically, I can't override the constructor in the MyBaseObject class. Trying to pass in MyRealCollection in place of MyBaseCollection isn't acceptable. If I get rid of the generics arguments, it works; MyRealCollection is accepted in place of MyBaseCollection. But I really need the generics argument to make my collection classes work the way I need them to.

I suggest you look into contravariance and covariance. Here might be a good start http://msdn.microsoft.com/en-us/library/dd799517.aspx
In short, the CLR can't assume what you want it to assume with respect to the type inheritance for some very well-defined reasons that are way above my pay grade.
However, you can do something like this if you play with the type hierarchy a little. I used IEnumerable to help.
public abstract class MyBaseObject
{
public MyBaseObject(IEnumerable<MyBaseObject> parent)
{
this.Parent = parent;
}
public IEnumerable<MyBaseObject> Parent { get; set; }
}
public class MyRealObject : MyBaseObject
{
public MyRealObject(MyRealCollection parent)
: base(parent)
{ }
public new MyRealCollection Parent { get { return (MyRealCollection)base.Parent; } }
}
public class MyRealCollection : IEnumerable<MyRealObject>
{ }

MyRealCollection is not accepted in the place of MyBaseCollection because it is a collection of MyRealObject, not MyBaseObject. For an idea of why, imagine if the constructor for MyBaseObject did this:
public MyBaseObject(MyBaseCollection<MyBaseObject> parent)
{
this.Parent = parent;
parent.Add(new SomeOtherRealObject());
}
That would be perfectly legal from the perspective of MyBaseObject, but not if you had passed in an instance of MyRealCollection

Related

Derived classes with derived properties

I have 2 classes that are both derived from a base class X. The base class contains a property of a class T. Both subclasses of X should contain a property that's derived from T.
What I would like to achieve is to declare the a property of T in the base class X and have it used in several methods, while using the same property of T in the derived classes of X but have it recognized as a derived class from T, so that I won't have to cast it every time I want to use it.
One of my solutions would be just remove the property from the base class and copy the methods for each derived class of X, but that would defeat the purpose of using inheritance.
Is anything like that achievable?
internal class TestObject
{
public string ID;
public XObject obj;
//....
}
internal class TestDocument : TestObject
{
public XDocument obj; //<--- want to be able to call obj in my methods
//as if it were an XDocument type but relate to the obj property in the base class
//....
}
internal class XObject
{
//....
}
internal class XDocument : XObject
{
//....
}
Generics should work for you:
class Base<T> where T: MyType
{
T MyProperty { get; set; }
public void DoSomething()
{
// do something with MyProperty
}
}
with MyType being the base-class of the property within Base.
Then in your derived class you can define the generic constraint, e.g.
class Derived : Base<DerivedType>
{
}
Now an instance of Derived has the property MyProperty of type DerivedType instead of MyType.
So in your case TestObject should be similar to this:
internal class TestObject<T> where T: XObject
{
public string ID;
public T obj;
//....
}
internal class TestDocument : TestObject<XDocument>
{
// obj is here of type XDocument
}
Make the type of the property a generic parameter of your base class:
class PropertyTypeBase { }
class PropertyTypeA : PropertyTypeBase { }
class Base<T> where T : PropertyTypeBase
{
public T Property { get; }
}
class Foo : Base<PropertyTypeA>
{
public Foo()
{
PropertyTypeBase x = Property;
PropertyTypeA a = Property;
}
}
The simplest way would be to make the base class generic, and constrain the generic parameter to be derived form a certain class:
class BaseProp { }
class DerivedPropA: BaseProp { }
class DerivedPropB : BaseProp { }
abstract class X<T>
where T: BaseProp
{
public T Value { get; set; }
public abstract void With(T value);
}
class A : X<DerivedPropA>
{
public override void With(DerivedPropA value)
{
this.Value = value;
}
}
class B : X<DerivedPropB>
{
public override void With(DerivedPropB value)
{
this.Value = value;
}
}
This is possible by using generics.
First, let me explain the example classes. Let's say these are your properties:
public class BaseHead {}
public class OrganicHead : BaseHead {}
public class CyborgHead : BaseHead {}
And you now want to implement these heads on your person classes:
public class BaseCreature {}
public class OrganicCreature : BaseCreature {}
public class CyborgCreature : BaseCreature {}
The solution:
public class BaseCreature<THead> where THead : BaseHead
{
public THead Head { get; set; }
public BaseCreature(THead head)
{
this.Head = head;
}
}
We make the BaseCreature generic
We limit the THead type to only allow types that either are BaseHead or are derived from BaseHead
However, we also want to ensure that the right creature (organic/cyborg) only uses the correct head (organic/cyborg). This can be done by deriving from a BaseCreature with a specific generic type:
public class OrganicCreature : BaseCreature<OrganicHead>
{
public OrganicCreature(OrganicHead head) : base(head)
{
}
}
CyborgCreature is analogous.
Suppose you wanted to make it possible that every creature can use every type of head. If that's what you want, then you need to keep the generic parameter generic:
public class OrganicCreature<THead> : BaseCreature<THead> where THead : BaseHead
{
public OrganicCreature(THead head) : base(head)
{
}
}
CyborgCreature is analogous.

Inheritance of types when using typeof

I'm trying to create a class structure like this:
public abstract class ParentClass
{
protected virtual void BuildQueries()
{
var Engine = new FileHelperEngine(typeof(TopType));
DataPoints = Engine.ReadFile(ResumeName) as TopType[];
}
protected Parent TopType;
}
public class ChildClass : ParentClass
{
protected override Child TopType
}
and the types:
public abstract class Parent
{
//some class members here
}
public class Child : Parent
{
//some class members here
}
I think there's an easy answer here, but I'm just too new to C# to figure out what I should be googling. I've tried using generics and I just can't get it right.
I know that without the inheritance I'd write
var Engine = new FileHelperEngine(typeof(Parent));
But this is the part of the inheritance that I'm struggling to figure out.
Sorry I failed to mention that FileHelperEngine references the FileHelpers C# library
I do think you're looking for generics, but I'm not totally sure because your question is not clear...
public abstract class ParentClass<T> where T : Parent
{
protected virtual void BuildQueries()
{
var Engine = new FileHelperEngine<T>();
var r = Engine.ReadFile(ResumeName);
}
protected T TopType { get; set; }
// (...)
}
public class ChildClass : ParentClass<Child>
{
// don't need to override anything, because your property is generic now
// which means it will be of type `Child` for this class
}
public class FileHelperEngine<T>
where T : Parent // this generic constraint might not be necessary
{
public T[] ReadFile(string name)
{
}
}

Creating a virtual generic method in C#

I have some base classes like this:
public class AbstractData
{
public int ID { get; set; }
}
public class Person: AbstractData
{
public string Name { get; set; }
}
public class AbstractManager<T> where T: AbstractData
{
public virtual List<T> GetAll()
{
}
public virtual T GetOne(int id)
{
}
}
public class PersonManager: AbstractManager<Person>
{
public override List<Person> GetAll()
{
//...
}
public override Person GetOne(int id)
{
//...
}
}
Now, I have a Windows Forms base class, like this:
public class BaseForm: Form
{
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
{
return null;
}
}
and a derived form:
public class PersonForm: BaseForm
{
public override AbstractManager<T> GetManager<T>()
{
return new PersonManager();
}
}
The problem is, I keep getting compile errors on the PersonForm class:
Cannot implicitly convert type 'PersonManager' to 'AbstractManager<T>'
Is there a way in which I can create this virtual method and have every class derived from BaseForm return the concrete representation of the AbstractManager?
If I get rid of the generic on the AbstractManager class then I compile OK (with a few code changes), but then the GetAll method can't return a List<T>. It would have to return a List<AbstractData> instead, which causes issues in converting from List<Person> to List<AbstractData>.
Any help would be appreciated.
First off all, please never do this:
class C<T>
{
void M<T>(T t) { }
}
Now we have two things named T both in scope and they are different. This is legal but extremely confusing. Choose better names for your type parameters.
Let's simplify your example:
class FruitBasket<T> where T : Fruit { }
class AppleBasket : FruitBasket<Apple> { }
class C
{
public static FruitBasket<T> GetBasket<T>() where T: Fruit
{
return new AppleBasket();
}
}
Now do you see why this is wrong? What if someone calls C.GetBasket<Orange>() and you hand them a basket of apples?
Any help would be appreciated.
What's step one of getting out of a hole? STOP DIGGING.
You have Genericity Happiness Disease, which is common to C# programmers who are discovering the power of the generic type system and then want to use it for everything whether that makes sense or not. Stop trying to capture all the relationships in your business process in the generic type system; that's not what it was designed for.
The test is: can you say "an apple basket is a basket of apples, where apples are a kind of fruit" and have someone who is not a programmer agree with you? Yes. Can you say "a person manager is an abstract manager of persons where person is a kind of abstract data" and have someone who is not a programmer agree with you? No. Then you are not successfully modeling the business domain in the type system. Start over, avoid generics, and try to come up with relationships between types that make sense.
By declaring
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
in BaseForm, you're promising that every class derived from BaseForm supports GetManager for any type T. For example, if you had another AbstractData subclass named Invoice, then you could write
personForm.GetManager<Invoice>()
and PersonForm would be expected to return an InvoiceManager.
If you want every class derived from BaseForm to support GetManager for only one type T, then move the T type parameter from GetManager to BaseForm:
public class BaseForm<T>: Form where T: AbstractData
{
public virtual AbstractManager<T> GetManager()
{
return null;
}
}
public class PersonForm: BaseForm<Person>
{
public override AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}
UPDATE: Chad Henderson points out that the Windows Forms designer can't handle generic base classes. If that's a problem for you, then you could try an alternate approach:
public interface IForm<T> where T: AbstractData
{
AbstractManager<T> GetManager();
}
public class BaseForm: Form
{
// ... base functionality that doesn't depend on T ...
}
public class PersonForm: BaseForm, IForm<Person>
{
public AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}

Generic objects in c#

i have a litte problem and i need some help :)
For example i have a simle abstract class
public abstract class BaseDefinition
{
public int Id { get;set; }
public string Name { get;set; }
}
and other base class
public abstract class BaseParentClass
{
public string Name { get;set; }
public string Schema { get;set; }
}
and first generic abstract class
public abstrac class BaseParentClass<T> :
BaseParentClass where T : BaseDefinition
{
public IList<T> Objects {get;set;}
}
and first implementations
public class ClassADefintion : BaseDefinition
{
public bool IsChanged {get;set;}
}
public class ClassAObject : BaseParentClass<ClassADefinition>
{
public bool OtherField {get;set;}
}
public class ClassBDefintion : BaseDefinition
{
public bool IsBBBChanged {get;set;}
}
public class ClassBObject : BaseParentClass<ClassBDefinition>
{
public bool OtherBBBBField {get;set;}
}
Sorry for class name, but I can't create anything better (it's only example)
As We see, now is all OK :).
I have some methods who returns a IEnumerable of generic implementation
IEnumerable<ClassBObject> ClassBObjectCollection;
IEnumerable<ClassAObject> ClassAObjectCollection;
Now i must create a method, who can take a generic objects in IEnumerable
public void DoWork(IEnumerable<BaseParentClass<BaseDefinition>> objects)
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
How i remember BaseObject<BaseDefinition> != ClassAObject, but compiler doesn't put on screen any errors. I remember in .NET in generic interface We can use IN and OUT T, so i try make this
public interface IBaseParentClass<out T> where T : BaseDefinition
{
IList<T> Objects {get;set;}
}
Yup, You can't make a List of <out T>. Somebody have any idea for this problem ?
I can get this fields values by reflection, but i have abstract class and interface so i think is a better way.
I don't have a compiler at hand, but I think it should be possible to rewrite DoWork as such:
public void DoWork<T>(IEnumerable<BaseObject<T>> objects)
where T : BaseDefinition
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
I am not sure whether the compiler will be able to infer T for you, try it out.
Another possibility may be that if you enumerate those objects anyway, to make Objects of Type IEnumerable(Of T).

Generics and Inheritance: How to use the parent in the child class?

I just try to redesign my Silverlight-4 App and tried a bit around with generics.
Simply speaking, I have a tree which can contain 2 types of nodes. As a base class, I created a class that does all the "organization", like having a list of children, a parent, a method to add a child and so on:
public abstract class BaseNode<T> : INotifyPropertyChanged where T: BaseNode<T>
{
protected ObservableCollection<T> _children;
...
}
Second, I add a class that inherits from BaseNode and is the basis for all my treenodes:
public class ServiceNodeBase<T> : BaseNode<ServiceNodeBase<T>> where T : ServiceNodeBase<T>
{
public string Description { get; set; }
...
}
And finally, as I can have two different kinds of nodes, I create a class for each kind, i.e.:
public class ServiceNodeComponent<T> : ServiceNodeBase<ServiceNodeComponent<T>> where T : ServiceNodeComponent<T>
{
public HashSet<Attributes> Attributes { get; set; }
...
}
In the ServiceNodeComponent, I need a method, that scans the tree i.e. to get all the child nodes, that are of the Type ServiceNodeComponent. When parsing the tree, I need to use the parent-type of ServiceNodeComponent (ServiceNodeBase), because the child nodes can also be of the other type.
Now, I do not know how to instantiate the ServiceNodeBase-Variable.
public HashSet<ServiceNodeComponent<T>> GetAllChildComponents()
{
// declaring the container for the found Components is no problem
HashSet<ServiceNodeComponent<T>> resultList = new HashSet<ServiceNodeComponent<T>>();
// but now: how to declare the container for the ServiceBaseNodes?
HashSet<ServiceNodeBase<???>> workingList = new HashSet<ServiceNodeBase<???>>();
Any ideas, how I would implement this?
Thanks in advance,
Frank
The problem is the constraint. It would work if you change it to
public class ServiceNodeComponent<T> : ServiceNodeBase<ServiceNodeComponent<T>>
where T : ServiceNodeBase<T> {
public HashSet<ServiceNodeComponent<T>> GetAllChildComponents() {
// ...
HashSet<ServiceNodeBase<T>> workingList = new HashSet<ServiceNodeBase<T>>();
// ...
}
}

Categories

Resources