扩展已经继承了另一个类

时间:2015-11-25 12:53:38

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

我继承了一些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;
    }
}

5 个答案:

答案 0 :(得分:2)

想法:

  1. 为公共属性创建新类型

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

  3. 实施:

    // 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;
        }
    }
    

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

您可以使用合成,而不是继承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的属性,以便你可以得到他们的财产。

答案 4 :(得分:0)

如果你需要利用扩展控件的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; } }
}