【问题标题】:C# Inheritance with generic interfaces and fluent methods具有泛型接口和流式方法的 C# 继承
【发布时间】:2021-10-19 14:48:10
【问题描述】:

我正在尝试弄清楚如何构建接口的通用结构以使用流畅的表示法。

我正在尝试如下结构:

public interface IGeneric<out T>
    where T : IGeneric<T>
{
    T Foo1();
    T Foo2();
    T Foo3();
}

public interface ISpecific_1 : IGeneric<ISpecific_1>
{ }

public interface ISpecific_2 : IGeneric<ISpecific_2>
{
    ISpecific_2 Bar1();
    ISpecific_2 Bar2();
    ISpecific_2 Bar3();
}

public abstract class GenericImpl<T> : IGeneric<T>
    where T : IGeneric<T>
{
    public T Foo1()
    {
        //Do things
        return (T)(object)this;
    }

    public T Foo2()
    {
        //Do things
        return (T)(object)this;
    }

    public T Foo3()
    {
        //Do things
        return (T)(object)this;
    }
}

public class SpecificImpl1 : GenericImpl<ISpecific_1>, ISpecific_1
{

}

public class SpecificImpl2 : GenericImpl<ISpecific_2>, ISpecific_2
{
    public ISpecific_2 Bar1()
    {
        //Do things
        return this;
    }

    public ISpecific_2 Bar2()
    {
        //Do things
        return this;
    }

    public ISpecific_2 Bar3()
    {
        //Do things
        return this;
    }
}

IGeneric 只接受它自己的实现作为 T,以确保 Foo1()、Foo2() 和 Foo3() 将返回正确的流利表示法类型。

GenericImpl 是抽象的(不是强制性的,但我想让它们使用特定的类)并实现 IGeneric。

ISpecific_1 使用自己的类型实现 IGeneric(这意味着 Generic 类中的 Foos 方法将返回 ISpecific_1)。

Specific_1 实现了 ISpecific_1 并扩展了 GenericImpl

ISpecific_2 和 Specific_2 相同,除了一些 Bars 额外方法。

这似乎可行,因为我可以这样做:

ISpecific_1 spec1 = new Specific_1();
spec1.Foo1().Foo2().Foo3(); //Everyone returns ISpecific_1 that extends the Generic class with the Foos

ISpecific_2 spec2 = new Specific_2();
spec2.Bar1().Foo1().Bar2().Foo2().Bar3().Foo3(); //Everyone returns ISpecific_2 with the Bars. Also the Generic Foos methods are available.

虽然我不能这样做:

ISpecific_1 spec1 = new Specific_1();
spec1.Bar1().Bar2().Bar3(); //ISpecific_1 nor IGeneric don't declare Bars methods

现在是问题:

第一个: 在 Foos 方法中,我必须使用手动转换返回值

return (T)(object)this;

我也可以制作 T : 类并使用

return this as T;

他们是安全的还是我错过了一个演员失败的案例?

第二个: 有没有更好的方法来做到这一点?

提前谢谢你

【问题讨论】:

  • “IGeneric 只接受它自己的实现作为 T” - 我不相信这是可能的,并且可能会导致循环依赖!
  • 这被称为奇怪的重复模板模式,你可以做类似public class MyThing : GenericImpl&lt;ISpecific_2&gt; 这样的事情,所以现在T 不会是MyThing,但因为ISpecific_2 是@987654330 @ 所以请注意,它不能保证泛型类型正是实现类的类型。
  • @phuzi 一开始我也是这么想的,当我发现我错了我也很惊讶。
  • @juharr 好点,没想到这一点。谢谢!
  • 问题中的代码是安全的,因为它会始终失败(因为 GenericImpl 永远不会是 T) - 请澄清问题,如果它是您所询问的安全类型

标签: c# generics interface casting fluent


【解决方案1】:

最后我找不到任何真正干净的解决方案:我不得不牺牲一点结构。

我几乎公开了所有属性(在我的情况下这不是问题);这使我可以将所有方法作为通用扩展方法而不是类方法来管理,并且它们仍然可以对公共属性进行操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 2013-10-04
    相关资源
    最近更新 更多