【问题标题】:C# Class following an interface and contains methods from abstract遵循接口并包含抽象方法的 C# 类
【发布时间】:2012-12-29 07:26:17
【问题描述】:

我尝试实现以下目标:我有一个名为 IAxis 的接口,它强制我的类 TheAxis 具有某些方法。另外我想实现某种基于参数的抽象类。为了解释这一点,将其写在代码中:

class TheAxis : IAxis
{
     public TheAxis(){ }

     public void IMoveToPos(int pos) {} //This is forced by the Interface


}

当这个类的实例被调用时,它应该能够选择包含哪些方法,类似于虚拟方法,但不会覆盖现有方法,而是添加来自另一个类的已经编码的方法。我正在寻找这样的东西:

abstract class GateAxis
{
    public void CloseGate() { IMoveToPos(0); }
}

abstract class XAxis
{
    public void MoveToStart() { IMoveToPos(100); }
}

TheGateAxis = new Axis() as GateAxis;

现在我希望能够使用 TheGateAxis.Closegate();但不是 TheGateAxis.MoveToStart();

如果我打电话

TheXAxis = new Axis() as XAxis;

我希望能够使用 TheXAxis.MoveToStart();但不是 TheXAxis.CloseGate();

XAxis 或 GateAxis 中给出的方法不需要 TheAxis 中的任何方法,除了接口给出的一次。

有可能做这样的事情吗?在实例化类时根据给定的参数向类添加方法?

我希望你能明白我正在努力做的事情,因为我很难解释。

最好, 凯文

【问题讨论】:

  • 我不确定我是否理解。如果您知道在初始化期间要使用哪个类,那么为什么不将其声明为该类的变量。例如:XAxis TheXAxis = new XAxis();
  • 你是从VB来的吗?在 C# 中,不要使用 as GateAxis 指定创建的类,而应该使用正确的构造函数:new GateAxis()
  • 嗨,不,我不是来自 VB。我想到了“作为想法”来寻找解决方案并找到虚拟课程。我只是使用了符号。我不想使用 XAxis TheXAxis = new XAxis();因为我需要在所有不同的类中声明 MoveToPos(int pos),尽管它们完全相同。我的程序中有 6 或 7 种类型的轴,并且以完全相同的方式定义相同的方法 6 或 7 次对我来说似乎是不好的做法。此外,代码以后将很难编辑(因为您需要在任何地方更改代码)
  • @Kevin as 运算符仅用于强制转换。除非你还使用GateAxis 的构造函数或派生类型,否则它将返回null。在这种情况下,您应该将其完全删除。

标签: c# .net interface abstract


【解决方案1】:

好吧,如果您希望类共享基类中的几个方法,而其他方法是分开的,您可以这样做

//an interface (optional)
public interface IAxis {
   void MoveToPos(int pos);
}

public abstract class AxisBase : IAxis {
   public void MoveToPos(int pos) {
      //implementation
   }
}

//optionally you can do an IGateAxis interface, inheriting (or not) from IAxis
public interface IGateAxis : IAxis {
   void CloseGate();
}

//classes inheriting from AxisBase, implementing IGateAxis
public class GateAxis : AxisBase, IGateAxis {
   public void CloseGate() {
      MoveToPos(0);
   }
}
//another interface, not inheriting from IAxis
public interface IXAxis {
   void MoveToStart();
}

//another class inheriting from AxisBase
public class XAxis : AxisBase, IXAxis {
   public void MoveToStart() {
     MoveToPos(100);
   }
}

用法

var gateAxis = new GateAxis();
gateAxis.CloseGate();
//and you can do
gateAxis.MoveToPos(250);

var xAxis = new XAxis();
xAxis.MoveToStart();
//and you can do
xAxis.MoveToPos(40);

使用 IGateAxis 接口

IGateAxis gateAxis = new GateAxis();
gateAxis.CloseGate();
gateAxis.MoveToPos(1);

使用 IXAxis 接口

 IXAxis xAxis = new XAxis();
 gateAxis.MoveToStart();
 //but you can't do 
 //gateAxis.MoveToPos(10);
//as IXAxis doesn't know about this method.

【讨论】:

  • 谢谢!这接近我正在寻找的东西。还有一个问题:我可以强制 XAxis: AxisBase 通过接口实现方法吗?类似:XAxis : AxisBase,IAxis 所以 XAxis 包含 AxisBase 的功能并且接口强制有其他方法?
  • @Kevin AxisBase 实现 IAxis,GateAxis 继承自 AxisBase,因此 GateAxis “也是”一个 IAxis。如果需要,您还可以创建一个 IGateAxis 接口,从 IAxis 继承(继承也适用于接口),并使 GateAxis 实现 IGateAxis。
  • @Kevin 为具有继承接口的示例编辑了答案。
  • 感谢拉斐尔!刚看到你的补充!谢谢,这是一个顺利的解决方案。
  • @Kevin : 是的,或者使用“MoveToPos”方法和 IXAxis 接口保留 IAxis,而不是从 IAxis 继承。
【解决方案2】:
    // super class
    abstract class TheAxis : IAxis {
        public TheAxis() { }

        public void IMoveToPos(int pos) { } //This is forced by the Interface


    }


    abstract class GateAxis : TheAxis {
        public virtual void CloseGate() { IMoveToPos(0); }
    }

    abstract class XAxis : TheAxis {
        public virtual void MoveToStart() { IMoveToPos(100); }
    }

现在,如果您从GateAxis 派生一个类,它将只能访问接口方法和来自GateAxis 的方法。 TheAxis 也是如此。

【讨论】:

  • 是的,除非 OP 有充分的理由,否则我相信这就是他所追求的。这两个派生类可能不应该是抽象的,因为他似乎想实例化它们。
  • 是的,但 OP 的问题尚不清楚,因此将做出假设。
  • 有时候我太盲目了,看不到明显的东西......谢谢!这也适用于实例化类吗?所以我可以打电话给XAxis TheXAxis = new XAxis?我想我只需要跳过摘要,不是吗?
  • 是的,抱歉 - 删除了我之前的评论,因为我没有正确阅读您的评论!。只需删除摘要即可。
【解决方案3】:

动态地添加方法并删除它们不是您在“正常”C# 中可以做的事情。没有任何 OOP 模式可以 模拟这一点。

可以做的是使用ExpandoObject 来实现完全您想要实现的目标。

代表一个可以动态添加成员的对象 在运行时删除。

顺便说一句,我不鼓励在静态类型语言领域使用它,所以稍微修改一下你的架构并且不要跳入 动态语言 域使用C#

【讨论】:

    【解决方案4】:

    我认为解决此问题的最佳方法是使用接口和单个(基)类。

    public interface IAxis {
        void MoveToPos(int pos);
    }
    
    public interface IGateAxis {
        void CloseGate();
    }
    
    public interface IXAxis {
        void MoveToStart();
    }
    
    public class TheAxis : IAxis, IGateAxis, IXAxis {
         public TheAxis(){ }
         void IAxis.MoveToPos(int pos) {} 
         void IGateAxis.CloseGate() { ((IAxis)this).MoveToPos(0); }
         void IXAxis.MoveToStart() { ((IAxis)this).MoveToPos(100); }
    }
    
    IGateAxis gateAxis = new ThisAxis();
    gateAxis.CloseGate();
    
    IXAxis xAxis = new ThisAxis();
    xAxis.MoveToStart();
    

    通过这种方式,您可以指定哪些方法可用于某些类型的轴。此外,您可以通过工厂模式甚至单个静态方法强制创建轴,以方便创建轴。

    【讨论】:

    • 显式接口实现不能有显式访问修饰符 (public void IAxis.MoveToPos(...)) ^_^
    • 正确,忘记使用 IAxis 实现删除它。
    【解决方案5】:

    假设您有 3 个以上的方法,我看到的最简单的方法是简单地创建一个充当责任链的代理:

    public class AxisProxy : IAxis
    {
        public AxisProxy(params IAxis[] implementations) {
            this.implementations = implementations;
        }
    
        private IAxis[] implementations;
    
        public virtual void CloseGate()
        { 
            foreach (var item in implementations) 
            {
                try { item.CloseGate(); } catch (NotSupportedException) {}
            }
            throw new NotSupportedException();
        }
    
        public virtual void MoveToStart() 
        {
            foreach (var item in implementations) 
            {
                try { item.MoveToStart(); } catch (NotSupportedException) {}
            }
            throw new NotSupportedException();
        }
    }
    

    您可以创建 Axis 的基本实现,以确保所有默认实现都抛出异常。派生实现实现特定功能。

    你可以通过调用来使用它

    IAxis myAxis = new AxisProxy(new GateAxis(), new XAxis());
    

    注意:在这种情况下,我会认真考虑将类型更改为“bool”;如果你经常调用这些方法,异常性能会增加......另外,由于 NotSupportedException 不会改变,你可以保留每个方法列表来删除抛出的实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 2017-10-12
      • 1970-01-01
      相关资源
      最近更新 更多