【问题标题】:Fluent interfaces and multiple inheritance in C#C# 中的流利接口和多重继承
【发布时间】:2013-08-02 21:34:15
【问题描述】:

这个问题类似于this one。不同之处在于我想要两个基类。

示例:

public class Circle
{
    private string _radius { get; set; }

    public Circle Radius(string radius)
    {
        _radius = radius;
        return this;
    }
}

public class Box
{
    private string _width { get; set; }

    public Circle Width(string width)
    {
        _width = width;
        return this;
    }
}

public class CircleAndBox : Circle, Box // Can't do in c#
{
    // should contain methods from both Circle and Box, but return CircleAndBox
}

也许圆形和盒子不是最好的例子。基本上它们代表具有不同属性和方法的类。 CircleAndBox 类恰好具有与 Circle 和 Box 相同的属性和方法。 CircleAndBox 可能具有 Circle 和 Box 中都不存在的其他属性和方法。

期望的结果

我应该会写:

var circle = new Circle().Radius("5");
var box = new Box().Width("6");
var circleAndBox = new CircleAndBox().Radius("5").Width("6");

如果:

当我向CircleBox 类添加方法时,我不应该接触CircleAndBox 类。就像从单个类的常规继承一样,CircleAndBox 应该自动继承 CircleBox 的所有公共方法

【问题讨论】:

  • Interfaces interfaces 接口...你需要这两个做什么?什么是圆+框?如果它是一个盒子里的圆圈,那么圆圈的半径是盒子宽度的一半?
  • .Width("6")??那么.Width("BigFat")??
  • new CircleAndBox().Radius("5").Width("6");这么流利了,我什至不明白这是什么意思。
  • @spender 如果 Radius 返回 CircleAndBox :P (怀疑!)
  • CircleAndBox 听起来非常违反里氏替换原则。

标签: c# inheritance multiple-inheritance fluent-interface


【解决方案1】:

CircleAndBox 既不继承自类,又继承自这些类的对象。它必须重新定义每个类的方法。您可以将隐式转换添加到 CircleBox 以允许在需要引用这些对象的上下文中使用它。

public class CircleAndBox
{
    public Circle Circle { get; private set; }
    public Box Box { get; private set; }

    public CircleAndBox()
    {
        Circle = new Circle();
        Box = new Box();
    }

    public CircleAndBox Radius(string radius)
    {
        Circle.Radius(radius);
        return this;
    }

    public CircleAndBox Width(string width)
    {
        Box.Width(width);
        return this;
    }

    public static implicit operator Circle(CircleAndBox self)
    {
        return self == null ? null : self.Circle;
    }

    public static implicit operator Box(CircleAndBox self)
    {
        return self == null ? null : self.Box;
    }
}

请注意,隐式转换不会保留对象的类型,因此不应使用此技术将CircleAndBox 传递给采用Box 的方法并期望另一端的结果是@ 987654327@.

CircleAndBox cb = new CircleAndBox();

// Implicit conversion, b contains a Box object.
Box b = cb;

// Compile-time error CS0030.
cb = (CircleAndBox)b;

【讨论】:

  • 请参阅问题的更新后的“如果:”部分。我知道您的解决方案无法解决这个问题?
  • @Dmitry C# 没有多重继承,所以如果不专门使用接口并在运行时通过代理类型自动提供委派方法,您的要求是不可能的。
  • 这听起来很聪明 :) 真的,我不太明白你在说什么。您是否建议仍有办法做到这一点,但它太复杂了?
  • @Dmitry 在不实现CircleAndBox 上的每个方法的情况下,唯一可以做到这一点的方法是创建 only interface ICircleAndBox : IBox, ICircle { },然后在运行。或者通过编写一个构建任务来检查其他两个接口并生成一个实现该接口的 C# 源文件。无论哪种方式,可能比重复每个实现都需要更多的工作。
【解决方案2】:

继承意味着“是一个”。

BallRoundThingCircleRoundThingBoxSquareThingLamborghiniCarCarTransportBusBicycle 也是 Transports。

如果不是“是”关系,则不是继承。这就是为什么 C# 和 Java 不支持多重继承的解释,我在 C++ 中认识的大多数人都不鼓励它。一个对象几乎不会同时是两个东西。

不要仅仅为了节省代码行而滥用继承。即使保存代码行是一个合法的目标(我不同意),它甚至没有必要。另外两个构造可以在这里为您提供帮助。

首先,关于关系。您正在寻找的是完全不同的关系。不是“is a”,而是“can be used as”。这就是接口的用武之地。接口指定对象可以用作什么。所以你可以有两个接口IBoxICircle。然后,您的 CircleAndBox 事物可以实现这两个接口,从而指定它可以用作两者。

其次,您可以多使用一种关系来让生活更轻松。您不会保存代码行。但是您将确保您的CircleAndBox 始终具有正确的行为,在CircleBox 类中定义。为此,您可以使用聚合以及委托模式。聚合是一种表示“具有”的关系。所以让你的CircleAndBox类有一个私有的Circle对象和一个私有的Box对象,然后通过调用各自的私有对象上的各自的方法/属性/事件来实现ICircleIBox接口,并且归还他们归还的东西。

Presto,你有一个类 有一个(聚合)Circle 和 Box 实例来实际传递工作,它通过具有相同的方法(委托)公开这些,因此 可以用作(界面)圆形用作盒子。

【讨论】:

  • 我不太关心节省代码行。我更关心可维护性。好好写! +1
【解决方案3】:

使用接口:

IBox 和 ICircle

public interface IBox
{
    Circle Width(string width)
}

public interface ICircle
{
    Circle Radius(string radius)
}

public class Circle : ICircle
{
    private int _radius { get; set; }

    public Circle Radius(string radius)
    {
        _radius = radius;
        return this;
    }
}

public class Box : IBox
{
    private int _width { get; set; }

    public Circle Width(string width)
    {
        _width = width;
        return this;
    }
}

public class CircleAndBox : ICircle, IBox
{
    // should contain methods from both Circle and Box, but return CircleAndBox
}

【讨论】:

  • (string Width) 无论如何都是个坏主意。字符串不是表示大小的合适数据类型。
  • 这只是他们所拥有的复制和粘贴,我同意。
  • 我不喜欢这种方法的原因是我仍然需要为 CircleAndBox 中的 ICircle 和 IBox 的每个方法编写实现。理想情况下,我想避免它。
【解决方案4】:

我认为你不能完全按照你的期望去做,因为 C#(和一般的 .Net)不支持类的多重继承。您可以从一个类继承并实现一个接口。

例如:

interface iBox
{
  iBox Width(string width); //Assuming you want Box here and not Circle
}

那么你就有了盒子

class Box : iBox ...

现在你可以拥有

public class CircleAndBox : Circle, iBox
{
private Box _helper;
public iBox Width(string width) { _helper.Width(width); return this; }
}

这并不完全是您想要的,但它与我认为的 C# 所允许的差不多。如果您愿意使用弱类型,还有一个委托方法可以将事物传递给 _helper,而无需显式实现每个方法。但是,通过直接委托,您不会返回您的 CircleAndBox 对象,而是 _helper 对象。我不确定这是否能达到目的。

此外,如果您不控制至少一个要继承的类,这将不起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 2013-02-07
    • 1970-01-01
    • 2012-05-13
    • 2018-04-30
    • 2013-12-06
    • 1970-01-01
    相关资源
    最近更新 更多