【问题标题】:extending a class that already inherits another class扩展一个已经继承另一个类的类
【发布时间】:2016-02-28 06:35:48
【问题描述】:

我继承了一些System.Windows.Forms-Control(大约10个)。 他们每个人都有一些自定义扩展,但大多数扩展对于每个控件都是相同的。

实际上,我必须为它们中的每一个单独编写相同的功能。 这需要大量的复制和粘贴,并且难以维护。

class MyButton : Button
{
    //this is only in MyButton
    public int ButtonProperty { get; set; }

    public object Property1 { get; set; }
    public object Property2 { get; set; }

    public void MakeInvisible()
    {
        this.Visible = false;
    }
}

class MyLabel : Label
{
    //this is only in MyLabel
    public bool LabelProperty { get; set; }

    //same propertys and methods as in MyButton
    public object Property1 { get; set; }//copy+paste
    public object Property2 { get; set; }//copy+paste

    public void MakeInvisible()//copy+paste
    {
        this.Visible = false;
    }
}

我正在寻找的是一种扩展所有派生类的方法,就像您可以使用 interface 或扩展方法一样。 但我也想拥有属性并访问基类 (Control)

这就是我的梦想:

class MyButton : Button, MyExtension
{   
    //this is only in MyButton
    public int ButtonProperty { get; set; }
}

class MyLabel : Label, MyExtension
{
    //this is only in MyLabel
    public bool LabelProperty { get; set; }
}

//Extension for all classes inherited from Control
class MyExtension : Control
{
    public object Property1 { get; set; }
    public object Property2 { get; set; }

    public void MakeInvisible()
    {
        this.Visible = false;
    }
}

【问题讨论】:

  • 我认为您应该对控件使用组合而不是继承,然后它是一个简单的基类和子类设置。
  • 你的意思是这样的? class MyButton : Button { public MyExtension = new MyExtension();}
  • 不,请参阅我的回答以了解我所说的示例。

标签: c# .net class controls extension-methods


【解决方案1】:

想法:

  1. 为通用属性创建新类型

  2. 为每个控件赋予该类型的属性

实现:

// TypeConverter required for PropertyGrid in design mode
// found here: http://stackoverflow.com/a/6107953/1506454
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MyExtension
{
    // need reference to control to work with in methods
    private Control _c;
    public MyExtension(Control c)
    {
        _c = c;
    }

    // can be inhereted for different controls, if necessary

    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public void MakeInvisible()
    {
        _c.Visible = false;
    }
}
// common interface of extended controls
public interface IExtended
{
    MyExtension Extra { get; }
}
// MyButton implements extended interface
public class MyButton : Button, IExtended
{
    public MyButton()
    {
        // create extended properties for button
        Extra = new MyExtension(this);
    }

    // for designer serialization support
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public MyExtension Extra { get; private set; }

    //this is only in MyButton
    public int ButtonProperty { get; set; }
}
// common extension methods
public static class MyControlHelper
{
    public static void MakeInvisible<TControl>(this TControl control) where TControl : Control, IExtended
    {
        control.Extra.MakeInvisible();
    }

    public static void Rename<TControl>(this TControl control) where TControl : Control, IExtended
    {
        control.Text = control.Extra.Property1;
    }
}

【讨论】:

  • 似乎是迄今为止最好的解决方案,因为它也是由 juharr 和医生建议的
【解决方案2】:

C# 不支持多继承。您应该尝试类似的方法 - MyButton : MyExtension;MyExtension : Button。在这种情况下,您将使用 MyExtension 和 Button 类扩展 MyButton 类。

【讨论】:

  • 如果我错了,请纠正我,但是我用这个解决方案赢得了什么?我必须为每个控件类型实现一个扩展:MyButtonExtension、MyLabelExtension、MyTextBoxExtension....
  • 是的,你在写。但是泛型呢?像这样 - MyControl,其中 T 是控制?
  • 嗯,从来没有使用过泛型,所以我必须看看在设计器中是否可行
【解决方案3】:

您可以为此目的使用扩展方法

public static class ControlHelper
{
    public static void MakeInvisible(this Control c)
    {
        c.Visible = false;
    }
}

并像这样使用它

var mb = new MyButton();
mb.MakeInvisible();

var ml = new MyLabel();
ml.MakeInvisible();

通过使用这种方法,您可以为基类生成扩展方法并在派生类中使用它。

【讨论】:

  • 是的,我知道,而且我也在我的问题中写了这个解决方案;)但这对属性没有帮助。 我正在寻找的是一种扩展所有派生类的方法,就像您可以使用接口或扩展方法一样。 但我也想拥有属性并访问基类(Control)
  • 你应该更喜欢组合而不是继承。
【解决方案4】:

您可以使用组合,而不是从 ButtonLabel 继承。

class MyExtension
{
    protected Control control;

    public MyExtension(Control control)
    {
        this.control = control;
    }

    public object Property1 { get; set; }
    public object Property2 { get; set; }
    public void MakeInvisible()
    {
        this.control.Visible = false;
    }
}

class MyButton : MyExtension
{
    public MyButton(Button button):base(button){}
    public int ButtonProperty { get; set; }
}

class MyLabel : Label
{
    public MyButton(Label label):base(label){}
    public bool LabelProperty { get; set; }
}

如果您不想创建任何实例,您甚至可以创建 MyExtension abstract。这里的主要区别是您必须创建一个ButtonLabel 才能传入,并且您可能希望将它们公开为MyButtonMyLabel 的属性,以便您可以获取它们的属性。

【讨论】:

  • 感谢您的想法,但在这种情况下,MyButton 和 MyLabel 不能在设计器中使用,因为它们不是控件。
【解决方案5】:

如果您需要利用扩展控件的 protected 方法和属性,那么您很不幸,如果不进行大量复制和粘贴,就无法实现您想要的。

如果您只需要访问公共方法和属性,那么请按照以下几行进行操作:

public interface IControlExtension
{
    Foo MyProperty { get; set; } 
    Blah MyMethod();
}

public abstract class ControlExtension: IControlExtension
{
     private Control owner;

     private ControlExtension(Control owner)
     {
         Debug.Assert(owner != null);
         this.owner = owner;
     }

     public static IControlExtension GetControlExtension(Control c)
     {
          if (c is Button ||
              c is Label)
          {
              return new SimpleControlExtension(c);
          }

          if (c is Panel || ...
          {
              return new ContainerControlExtension(c);
          }  
     }

     public abstract Foo MyProperty { get; set; }
     public abstract Blah MyMethod();

     private class SimpleControlExtension: ControlExtension
     {
          public override Foo MyProperty { .... }
          public override Blah MyMethod { .... 
     }

     private class ContainerControlExtension: ControlExtension
     {
          public override Foo MyProperty { .... }
          public override Blah MyMethod { .... }
     }
}

现在,在所有扩展控件中,复制和粘贴代码是最少的:

public class MyButton : Button
{   
    public MyButton()
    {
        ....
        var controlExtension = ControlExtension.GetControlExtension(this);
    }

    public IControlExtension { get { return controlExtension; } }
}

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 2012-12-07
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 2014-11-22
    • 2012-04-21
    相关资源
    最近更新 更多