C# 扩展已继承另一个类的类

C# 扩展已继承另一个类的类,c#,.net,class,controls,extension-methods,C#,.net,Class,Controls,Extension Methods,我继承了一些系统.Windows.Forms控件(大约10个)。 每个控件都有一些自定义扩展,但每个控件的大多数扩展都是相同的 实际上,我必须分别为它们编写相同的功能。 这是大量的复制+粘贴,很难维护 class MyButton : Button { //this is only in MyButton public int ButtonProperty { get; set; } public object Property1 { get; set; } p

我继承了一些
系统.Windows.Forms控件
(大约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;
    }
}
我正在寻找的是一种扩展所有派生类的方法,就像使用
接口
或扩展方法一样但我还希望拥有属性并访问基类(
控件

这就是我梦寐以求的:

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

C#不支持多重继承。您应该尝试这样的操作-
MyButton:MyExtension
MyExtension:按钮
。在本例中,您将使用MyExtension和Button类扩展MyButton类。

您可以使用扩展方法来实现此目的

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

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

您可以使用组合,而不是从
按钮和
标签继承

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的任何实例,您甚至可以将其制作成
MyExtension
abstract
。这里的主要区别是,您必须创建一个
按钮
标签
,然后才能传入,您可能希望将它们作为
MyButton
MyLabel
的属性公开,以便了解它们的属性。

想法:

  • 为公共属性创建新类型

  • 为每个控件指定该类型的属性

  • 实施:

    // 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;
        }
    }
    
    //通用扩展方法
    公共静态类MyControlHelper
    {
    publicstaticvoid使不可见(此TControl控件),其中TControl:control,IExtended
    {
    control.Extra.MakeInvisible();
    }
    publicstaticvoidrename(此TControl控件),其中TControl:control,IExtended
    {
    control.Text=control.Extra.Property1;
    }
    }
    
    如果您需要利用扩展控件的
    受保护的方法和属性,那么您就太倒霉了,如果不进行大量复制和粘贴,就无法实现您想要的

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

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

    我认为你应该使用组合来代替继承,然后是一个简单的基类和子类设置。你是说这样的吗
    class MyButton:Button{public MyExtension=new MyExtension();}
    No,请参阅我的答案以了解我所说的示例。如果我错了,请纠正我,但我用此解决方案赢得了什么?我必须为每种控件类型实现一个扩展:MyButtonExtension、MyLabelExtension、MyTextBoxExtension……是的,您正在编写。但是泛型呢?像这样-MyControl,其中T是control?嗯,从来没有使用泛型,所以我必须看看这在设计中是否可行。我知道,我还写了这个解决方案,这是我的问题;)但这对房产没有帮助。我要寻找的是一种扩展所有派生类的方法,就像使用接口或扩展方法一样。但是我还想拥有属性和访问基类(控件),你应该更喜欢组合而不是继承。谢谢你的想法,但在这种情况下,MyButton和MyLabel不能在designer中使用,因为它们不是控件。这似乎是迄今为止最好的解决方案,正如juharr和doctor所建议的那样
    // 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;
        }
    }
    
    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; } }
    }