我有一个继承/ extends公共接口的内部接口:
internal interface IFoo: IList<string>
{
void FooAdd(string item);
}
我只想允许IFoo
的成员以及IList<string>
的成员进行内部访问。 IFoo
的直接成员可以使用internal
关键字实施,但由于IList<T>
是公开的,我必须明确地实施它们:
public class MyClass: IFoo, IReadOnlyList<string>
{
// IFoo implementations:
internal void FooAdd(string item)
{
...
}
// Explicit IList<string> implementations:
void IList<string>.Add(string item)
{
...
}
// Public IReadOnlyList<string> members:
public int Count { get { return ... } }
}
现在,由于IFoo
接口是内部的,我的lib用户无法访问internal
中声明为MyClass
的已实现方法,这正是我的意图。但是,他们仍然可以通过投射访问IList<T>
成员,这是我没想到的:
var myClassObj = new MyClass<string>();
(myClassObj as IList<string>).Add("Haha, gotcha!");
在库之外,我原本以为编译器会抱怨没有办法将myClassObj
强制转换为IList<string>
,因为MyClass
只能通过内部接口实现此接口
我是否应该使用不同的模式,如果我希望我的类实现公共接口功能,那只应该在内部可用?
答案 0 :(得分:1)
我原本以为编译器会抱怨没有办法将
myClassObj
投射到IList<string>
编译器无法做到这一点。除非在非常有限的情况下,编译器会依次对待显式的强制转换和转换,并假设自从您编写它以来,就意味着它。在编译器总是在运行时失败的情况下编写代码并不难,即使编译器允许它,即使您可以查看代码并看到它总是会失败。
要了解原因,请考虑您的对象始终可以由object
类型的变量引用。当发生这种情况时,编译器不知道对象的声明实现。它不能阻止代码中的强制转换,即使已知强制转换是非法的。
当然,在运行时,唯一重要的是对象实际是否实现了接口。所以演员甚至都不是非法的。显式接口实现不会隐藏接口。它只是强制要求除了通过该接口类型的表达式之外不能使用该实现。它根本不是控制可访问性的手段。
如果您不希望外部代码在外部代码可以访问的对象中看到您的IList<T>
实现,那么您必须实际隐藏该代码。唯一的方法是更改您的设计,以便您的对象 IList<T>
而不是 IList<T>
(即组合vs.继承),IList<T>
只能访问您想要的代码(例如,由标记为internal
的属性公开)。
请记住,即便如此,可访问性主要是编译时安全功能。无论可访问性如何,在完全信任环境中(即在绝大多数托管代码执行的上下文中)的反射将始终允许访问对该对象具有访问权限的任何代码。为了鼓励正确使用您的类型,限制访问是一件好事,但它本身并不是一个安全功能(尽管它可以与之结合使用)。