为啥在接口列表的泛型类型中使用私有嵌套类型不是“不一致的可访问性”?
Posted
技术标签:
【中文标题】为啥在接口列表的泛型类型中使用私有嵌套类型不是“不一致的可访问性”?【英文标题】:Why is it not "inconsistent accessibility" to use a private nested type inside a generic type in the interface list?为什么在接口列表的泛型类型中使用私有嵌套类型不是“不一致的可访问性”? 【发布时间】:2012-12-21 08:51:45 【问题描述】:如果标题不完全不言自明,下面是让我感到困惑的代码:
public interface IFoo<T>
public class MyClass : IFoo<MyClass.NestedInMyClass>
private class NestedInMyClass
我很惊讶这个编译没有错误。感觉就像我在暴露 private
类型。 这不应该是非法的吗?
也许你的答案只是“没有规则反对,那为什么不行呢?”也许同样令人惊讶的是MyClass.NestedInMyClass
甚至在“范围”内。如果我删除MyClass.
资格,它将无法编译。
(如果我将IFoo<>
更改为通用类,它应该成为MyClass
的基类,这是非法的,因为基类型必须是至少与类型本身一样易于访问。)
我用 Visual Studio 2010 的 C# 4 编译器尝试了这个。
【问题讨论】:
我想知道如果你在 IFoo 中创建一个返回或接受 T 的函数会发生什么。我现在没有 PC 来测试它。 @Euphoric 我正要问这个问题。最有可能的是,这只是允许的,因为 IFoo 是一个接口,因此不能对嵌套类“做”任何事情。在这种情况下,在方法中公开它应该是非法的。据我所知,这将使此功能非常无用。 @Euphoric 刚刚尝试这样做。向Foo
添加了一个接受T
的方法,实现了(noop)实现,并且该方法可在MyClass
的实例上调用(我只能传入null
以使其编译,因为我无法从外部获取实例)。请注意,如果该方法返回 T
,那么您将通过在外部公开 NestedInMyClass
来获得“不一致的可访问性”的编译器错误。
@Euphoric 如果IFoo<T>
包含使用T
的任何成员,则似乎无法编写IFoo<T>
的实现。
@JeppeStigNielsen 你试过显式接口实现吗?
【参考方案1】:
没有外部代码可以将对象转换到这个接口,所以这不是可访问性问题。
public
类甚至被允许实现private
或internal
接口——同样地,外部代码实际上不能发生cast。
Re:关于依赖于T
的实现的讨论 - 如果您使用显式接口实现,您将被允许 - 因为在这种情况下,接口的方法实际上是私有的。例如:
public interface IFoo<T>
void DoStuff(T value);
public class MyClass : IFoo<MyClass.NestedInMyClass>
void IFoo<MyClass.NestedInMyClass>.DoStuff(MyClass.NestedInMyClass value)
private class NestedInMyClass
有效(因为接口实现方法没有被类本身公开)。
【讨论】:
@Servy 你确定方法是公开的而 NestedInMyClass 是私有的吗? @Servy 你能发布你的代码吗?当我将该方法标记为公开时,我得到一个不一致的可访问性错误。 没关系,你是对的。我在玩,无法再次复制它,一定是有什么不太对劲。 那么如果public
(非嵌套)类C
实现IEnumerable<Secret>
,其中Secret
是不是public
的类型怎么办? (对于这个例子,C
不包含public
GetEnumerator()
方法,只有显式接口实现。)假设有人可以看到C
并拥有它的一个实例,但由于可访问性而看不到Secret
。他们可以通过他们的实例foreach
吗?我猜他们可以因为非通用的IEnumerable
接口。如果foreach
变量是隐式类型的(foreach (var x in instanceOfC) ...
中的var
)怎么办?
如果他们实现了IEnumerable<Secret>
,那么他们必须使用显式接口实现。这意味着只有将IEnumerator<T>
s GetEnumerator
方法cast 转换为IEnumerable<Secret>
后才能访问它——它不是类上的公共方法。而且你不能做演员,因为Secret
不可访问。 (当然,所有这些“不能投射”的东西都忽略了反射)【参考方案2】:
类实现接口这一事实意味着可以创建接口类型的存储位置的代码可以在该存储位置存储对该类型的引用,并且可以使用该存储位置上的接口成员。它没有提供任何新的编码能力,否则将无法创建该类型的存储位置。
让一个公共类Foo
实现一个私有或内部类型IBar
的接口,使有权访问IBar
的代码能够将Foo
引用转换为IBar
。 Foo
可被无权访问IBar
的代码访问这一事实绝不意味着它也不会被具有此类访问权的代码使用。实际上,定义Foo
的程序集或类想要使用外部世界不可用的Foo
的特性是很正常的;事实上,它实现了IBar
只是这样一个特性。
【讨论】:
以上是关于为啥在接口列表的泛型类型中使用私有嵌套类型不是“不一致的可访问性”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能在编译时将整数添加到泛型集合中,即使使用引用类型作为数字创建的泛型? [复制]