I am using a fictional example for this. Say, I have a Widget class like:
abstract class Widget
{
Widget parent;
}
Now, my other classes would be derived from this Widget class, but suppose I want to put some constraint in the class while defining the derived types such that only a particular "type" of widget can be parent to a particular type of Widget.
For example, I have derived two more widgets from the Widget class, WidgetParent and WidgetChild. While defining the child class, I want to define the type of parent as WidgetParent, so that I dont have to type cast the parent every time I use it.
Precisely, what I would have liked to do is this:
// This does not works!
class Widget<PType>: where PType: Widget
{
PType parent;
}
class WidgetParent<Widget>
{
public void Slap();
}
class WidgetChild<WidgetParent>
{
}
So that when I want to access the parent of WidgetChild, instead of using it this way:
WidgetParent wp = wc.parent as WidgetParent;
if(wp != null)
{
wp.Slap();
}
else throw FakeParentException();
I want to use it this way(if I could use generics):
wc.parent.Slap();
-
I don't think there is a language mechanism that would allow you to do that.
However, you might want to use a Factory pattern to separate the construction of the class from the class itself.
Say, make a WidgetFactory class
class WidgetFactory { Widget CreateWidget() { return new Widget(); } }
And for child classes, you'd make their factory as well. Say, a WidgetParentFactory or WidgetChildFactory or you could make a generic factory:
class WidgetFactory<T> where T : Widget { T CreateWidget() { return new T(); } }
Then from the CreateWidget() method you could control class instantiation so that invalid child types can not be created.
class WidgetFactory<T> where T : Widget { T CreateWidget() { if (/*check the type T inheritance here*/) return new T(); else throw new Exception("Invalid inheritance"); } }
This should do the trick for you.
p.s. Would you care to elaborate on why you wanted to do this?
nullDev : Thanks for the effort, chakrit. I have elaborated the usage.chakrit : Ok I see now. Will edit when I got home. -
You should be able to use the code you've got by still having the non-generic class
Widget
and makingWidget<T>
derive from it:public abstract class Widget { } public abstract class Widget<T> : Widget where T : Widget { }
You then need to work out what belongs in the generic class and what belongs in the non-generic... from experience, this can be a tricky balancing act. Expect to go back and forth a fair amount!
-
You seem to be confusing type parameters and inheritance. This should work:
class Widget<PType> where PType :new() { public PType parent = new PType(); } class ParentType {} class WidgetParent : Widget<ParentType> { public void Slap() {Console.WriteLine("Slap"); } } class WidgetChild : Widget<WidgetParent> { } public static void RunSnippet() { WidgetChild wc = new WidgetChild(); wc.parent.Slap(); }
Jon Skeet : I'd assumed the point was to constrain the parent type to also be a widget of some kind though.nullDev : @Jon: Exactly,the parent has the said constraint. -
Use interfaces:
interface IContainerWidget { } class Widget { private IContainerWidget Container; } class ContainerWidget : Widget, IContainerWidget { }
-
Here's my stab at organizing this.
public interface IWidget { void Behave(); IWidget Parent { get; } } public class AWidget : IWidget { IWidget IWidget.Parent { get { return this.Parent; } } void IWidget.Behave() { this.Slap(); } public BWidget Parent { get; set; } public void Slap() { Console.WriteLine("AWidget is slapped!"); } } public class BWidget : IWidget { IWidget IWidget.Parent { get { return this.Parent; } } void IWidget.Behave() { this.Pay(); } public AWidget Parent { get; set; } public void Pay() { Console.WriteLine("BWidget is paid!"); } } public class WidgetTester { public void AWidgetTestThroughIWidget() { IWidget myWidget = new AWidget() { Parent = new BWidget() }; myWidget.Behave(); myWidget.Parent.Behave(); } public void AWidgetTest() { AWidget myWidget = new AWidget() { Parent = new BWidget() }; myWidget.Slap(); myWidget.Parent.Pay(); } public void BWidgetTestThroughIWidget() { IWidget myOtherWidget = new BWidget() { Parent = new AWidget() }; myOtherWidget.Behave(); myOtherWidget.Parent.Behave(); } public void BWidgetTest() { BWidget myOtherWidget = new BWidget() { Parent = new AWidget() }; myOtherWidget.Pay(); myOtherWidget.Parent.Slap(); } }
-
I had a similar issue and adapted it to suit this (hopefully)
Main Code
public class Parent<T> where T : Child<T> { public Parent() { } public T Get() { return Activator.CreateInstance(typeof(T), new object[] { this }) as T; } } public class Child<T> where T : Child<T> { Parent<T> _parent; public Parent<T> Parent { get { return _parent; } } public Child(Parent<T> parent) { _parent = parent; } } public class ItemCollection : Parent<Item> { } public class Item : Child<Item> { public Item(Parent<Item> parent) : base(parent) { } }
Example :
ItemCollection col = new ItemCollection(); Item item = col.Get(); item.Parent.Slap();
0 comments:
Post a Comment