【问题标题】:How to have a public class inherit from private interface, without getting Inconsistent accessibility error如何让公共类从私有接口继承,而不会出现不一致的可访问性错误
【发布时间】:2015-02-25 04:21:17
【问题描述】:

以下是我想要做的解释:

public class MyClass
{
  public T GetFoo<T>() : where T : class, MyInterface
  {
    if (typeof(T) == typeof(Class1)
    {
      return new Class1() as T;
    }
    else if (typeof(T) == typeof(Class2))
    {
      return new Class2() as T;
    }
    else
    {
      return default(T);
    }
  }

  private interface MyInterface {}  // This is actually empty, it doesn't do anything except limit the types that can be passed to GetFoo()

  public class Class1 : MyInterface
  {
    // Stuff
  }

  public class Class2 : MyInterface
  {
    // Other Stuff
  }
  // there are many more such classes that all inherit from MyInterface
}

所以,我有一个带有公共方法的公共类。该方法接受一个泛型类型参数。但我想限制它接受的 T 类型,所以这就是它使用 MyInterface 的原因。 当然,因为 MyInterface 是私有的,所以无法编译。它抛出“不一致的可访问性:约束类型比”错误更难访问。

但这就是我希望它以这种方式工作的原因:

Class1、Class2 等中的每一个都被声明为 public,以便其他人可以使用它们。但我想限制其他人能够声明自己的此类类并将它们传递给 GetFoo() 方法。因为这会破坏 GetFoo(),所以我希望 MyInterface 是私有的。

如果我公开 MyInterface,它当然会编译并且一切都会正常工作。但我需要能够防止其他人声明自己的类并继承 MyInterface 并将其传递给 GetFoo()。

我想允许调用者这样做:

Class1 userFoo = GetFoo<Class1>();

我想阻止来电者这样做:

Class UserClass : MyInterface {}
...
UserClass userFoo = GetFoo<UserClass>();

编辑:感谢所有非常快速的回复。是的,我知道这不是 Interface 的目的,它当时对我来说似乎很有意义。如果存在更优雅的解决方案,我当然愿意接受。

【问题讨论】:

  • 如果界面是空的,你为什么要关心别人能不能看到呢?您不能以这种方式混合私有和公共。
  • 所以...你让调用者有责任确保类型实现MyInterface,但你不会给调用者一个机会来确保类型实现MyInterface?
  • 听起来你需要工厂模式。 msdn.microsoft.com/en-us/library/ee817667.aspx
  • 调用者应该能够做到这一点:Class1 userCode = GetFoo();调用者甚至不需要知道 MyInterface 存在。
  • @Wedge 约束验证(验证Class1 实现MyInterface)发生在调用站点,该接口不可见。

标签: c# generics types constraints


【解决方案1】:

你不能。这基本上是不可能的。通过创建接口private,调用者实际上不知道一个类是否实现了该接口。但是通过在类型约束中使用它,您确实需要调用者知道一个类是否实现了该接口。


您可以做的是使用一个公共基类:即使该类必须是public,您也可以阻止其他人从它派生。

public class Base {
  internal Base() { }
}
public interface IBase { }
public sealed class Class1 : Base, IBase {
  ...
}
public sealed class Class2 : Base, IBase {
  ...
}
public T GetFoo<T>() where T : Base, IBase {
  ...
}

IBase 接口是为了确保GetFoo&lt;Base&gt; 会被拒绝。 Class1Class2sealed 以防止其他人从中派生。

但是,这种方法只有在 Class1Class2 应该有一个共同的基类时才有效。


不过,我鼓励您重新考虑您的设计。几乎总是,如果您的通用代码有一堆typeof(T) == typeof(SomeConcreteClass) 条件,这强烈表明您最好为每种具体类型创建单独的方法。但也有例外,我不排除您的代码是例外之一的可能性。

【讨论】:

  • 是的,这行得通。但它引入了一些额外的混乱。拥有一个什么都不做的 Base 类似乎毫无意义。
  • 你说得对,我认为需要重新设计。在我最初的设计中,GetFoo() 返回了一个基类,用户必须将其拆箱。但我不喜欢装箱/拆箱,我不希望用户必须这样做。所以这就是我尝试泛型的原因。我确信有一种优雅的方式可以完成我想要的,只是我还没有找到它。
  • @Wedge 将GetClass1GetClass2 方法分开?或者你有这么多的类,维护起来会很痛苦?
  • 这是一种可能性,但实际上不仅仅是 2 个类,所以我认为这会很痛苦。此外,我真的很喜欢从调用者的角度来看泛型的工作方式。它为他们提供了一种调用方法,并让他们轻松获取属性。他们大部分时间将如何使用它实际上是这样的: var myProperty = GetFoo().Property1;
  • 我想我实际上是在尝试创建一个工厂模式,但我没有意识到这一点。除了工厂通常只创建一个类型。有没有不需要拆箱的通用工厂之类的东西?
【解决方案2】:

创建一个实现接口的类并尝试隐藏接口提供给您的抽象是毫无意义的。

OO 不是针对对象进行编程,这是您肯定要尝试做的事情,而是针对接口进行编程,并且您正试图隐藏它们。

最好考虑不同的方法。

【讨论】:

    【解决方案3】:

    这段代码可以工作并编译:

    public class MyClass<T> where T : class, IMyInterface
    {
        public T GetFoo()
        {
            if (typeof (T) == typeof (Class1))
            {
                return new Class1() as T;
            }
            else if (typeof (T) == typeof (Class2))
            {
                return new Class2() as T;
            }
            else
            {
                return default(T);
            }
        }
    }
    
    public interface IMyInterface {}  // This is actually empty, it doesn't do anything except limit the types that can be passed to GetFoo()
    
    public class Class1 : IMyInterface
    {
    // Stuff
    }
    
    public class Class2 : IMyInterface
    {
    // Other Stuff
    }
    // there are many more such classes that all inherit from MyInterface
    

    并且 Main 方法可以正常工作:

        static void Main(string[] args)
        {
            var a1 = new MyClass<Class1>();
            var a2 = a1.GetFoo();
        }
    

    【讨论】:

    • 是的,OP 已经提到过。但这允许随机的第三方类实现IMyInterface,而 OP 希望将其限制为 OP 自己的类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多