【问题标题】:Generic Parent For Generic Class泛型类的泛型父级
【发布时间】:2010-09-20 15:19:06
【问题描述】:

我为此使用了一个虚构的例子。说,我有一个像这样的 Widget 类:

abstract class Widget
{
Widget parent;
}

现在,我的其他类将派生自这个 Widget 类,但假设我想在定义派生类型时在类中设置一些约束,以便只有特定“类型”的小部件可以成为特定类型的父级小部件。

例如,我从 Widget 类派生了另外两个小部件,WidgetParent 和 WidgetChild。在定义子类的时候,我想把父类的类型定义为WidgetParent,这样我就不用每次使用都对父类进行类型转换了。

确切地说,我想做的是:

// This does not works!
class Widget<PType>: where PType: Widget
{
    PType parent;
}

class WidgetParent<Widget>
{
    public void Slap();
}

class WidgetChild<WidgetParent>
{
}

这样当我想访问 WidgetChild 的父级时,而不是这样使用它:

WidgetParent wp = wc.parent as WidgetParent;
if(wp != null)
{
    wp.Slap();
}
else throw FakeParentException();

我想以这种方式使用它(如果我可以使用泛型):

wc.parent.Slap();

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    您应该能够通过仍然拥有非泛型类 Widget 并让 Widget&lt;T&gt; 派生自它来使用已有的代码:

    public abstract class Widget
    {
    }
    
    public abstract class Widget<T> : Widget where T : Widget
    {
    }
    

    然后,您需要弄清楚什么属于泛型类,什么属于非泛型......根据经验,这可能是一个棘手的平衡行为。预计来回相当多!

    【讨论】:

      【解决方案2】:

      使用接口:

      interface IContainerWidget { }
      
      class Widget
      {
          private IContainerWidget Container;
      }
      
      class ContainerWidget : Widget, IContainerWidget
      {
      }
      

      【讨论】:

        【解决方案3】:

        我认为没有一种语言机制可以让你这样做。

        但是,您可能希望使用 Factory pattern 将类的构造与类本身分开。

        说,做一个 WidgetFactory 类

        class WidgetFactory
        {
            Widget CreateWidget()
            {
                return new Widget();
            }
        }
        

        对于子类,您也可以创建他们的工厂。比如说,一个 WidgetParentFactory 或 WidgetChildFactory 或者你可以创建一个通用工厂:

        class WidgetFactory<T> where T : Widget
        {
            T CreateWidget()
            {
                return new T();
            }
        }
        

        然后你可以通过 CreateWidget() 方法控制类的实例化,这样就不能创建无效的子类型。

        class WidgetFactory<T> where T : Widget
        {
            T CreateWidget()
            {
                if (/*check the type T inheritance here*/)
                    return new T();
                else
                    throw new Exception("Invalid inheritance");
            }
        }
        

        这应该对你有用。

        附言你愿意详细说明为什么你想这样做吗?

        【讨论】:

        • 感谢您的努力,chakrit。我已经详细说明了用法。
        【解决方案4】:

        您似乎混淆了类型参数和继承。这应该有效:

        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: 没错,父母有上述约束。
        【解决方案5】:

        这是我组织这个的尝试。

        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();
            }
        }
        

        【讨论】:

          【解决方案6】:

          我遇到了类似的问题,并对其进行了调整以适应这种情况(希望如此)

          主代码

          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)
              {
              }
          }
          

          示例:

          ItemCollection col = new ItemCollection();
          Item item = col.Get();
          item.Parent.Slap();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-05-30
            • 2022-10-14
            • 1970-01-01
            • 2020-09-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多