C# 将公共接口实现仅限于内部使用

C# 将公共接口实现仅限于内部使用,c#,inheritance,interface,internal,C#,Inheritance,Interface,Internal,我有一个继承公共接口的内部接口: internal interface IFoo: IList<string> { void FooAdd(string item); } 现在,由于IFoo接口是内部接口,因此我的库的用户无法访问在MyClass中声明的internal实现的方法,这正是我想要的。但是,他们仍然可以通过强制转换访问IList成员,这是我没有想到的: var myClassObj = new MyClass<string>(); (myClassO

我有一个继承公共接口的内部接口:

internal interface IFoo: IList<string>
{
    void FooAdd(string item);
}
现在,由于
IFoo
接口是内部接口,因此我的库的用户无法访问在
MyClass
中声明的
internal
实现的方法,这正是我想要的。但是,他们仍然可以通过强制转换访问
IList
成员,这是我没有想到的:

var myClassObj = new MyClass<string>();
(myClassObj as IList<string>).Add("Haha, gotcha!");
var myClassObj=new MyClass();
(myClassObj作为IList)。添加(“哈哈,明白了!”);
在库之外,我本以为编译器会抱怨没有办法将
myClassObj
转换为
IList
,因为
MyClass
只通过内部接口实现此接口

如果我想让我的类实现公共接口功能,是否应该使用一种只在内部可用的不同模式

我原以为编译器会抱怨没有办法将
myClassObj
强制转换为
IList

编译器没有办法做到这一点。除非在非常有限的场景中,否则编译器会尊重显式强制转换和转换,并假设既然您编写了它,就意味着它。编写在运行时强制转换总是失败的代码并不难,即使编译器允许这样做,即使您可以查看代码并发现它总是会失败

查看原因,请考虑您的对象总是由类型<代码>对象< /> >的变量引用。发生这种情况时,编译器不知道对象的声明实现。它不能阻止代码中的强制转换,即使已知强制转换是非法的

当然,在运行时,唯一重要的是对象是否真正实现了接口。所以演员阵容也不是违法的。显式接口实现不会隐藏接口。它只是要求实现只能通过该接口类型的表达式使用。它根本不是控制可访问性的手段

如果您不希望外部代码在外部代码可以访问的对象中看到您的
IList
实现,那么您必须对该代码隐藏它。唯一的方法是更改设计,使对象具有
IList
而不是
IList
(即组合与继承),并且
IList
仅可由所需代码访问(例如,由标记为
internal
的属性公开)


请记住,即使这样,可访问性主要还是编译时安全特性。完全信任环境中的反射(即,在绝大多数托管代码执行的上下文中)将始终允许访问任何代码,而不管可访问性如何。为了鼓励正确使用您的类型,限制访问是很好的,但它本身不是一种安全功能(尽管它可以与此类功能结合使用)。

感谢您的解释,我100%同意您的最后一段;我只打算限制代码访问以确保正确使用。关于前3段,我希望编译器会抛出一个错误,但我确实明白你的观点,在这种情况下,组合可能更适合。只有当编译器能够保证强制转换将失败时,才会发出CS0039。当然,这里的情况并非如此,因为正如我所描述的,将对象强制转换到它实现的公共接口实际上并不违法。反射将始终允许访问任何代码,无论其可访问性如何。你能为此提供参考吗?好的,尝试访问不可访问的成员将生成对
ReflectionPermission
的请求,当调用方不能满足请求时,这将导致
SecurityException
。@PetSerAl:您似乎被我的语句的语义搞糊涂了。反射始终允许访问,但调用方可能并不总是能够访问反射。这就像说“一个人总能从我的冰箱里得到冰”,这是真的,即使某些特定的人无法进入我的冰箱(例如,我没有让他们进入我的房子)。如果您有一些不同的措辞,您认为会更好,请随意提出一些建议。据我所知,在当前的.NET Framework版本中,始终允许访问反射。您可以自由枚举所有成员,包括不可访问的成员,并调用任何可访问的成员。对无法访问的成员的调用受到限制。因此,除非您将权限分配搞砸,并将非常敏感的权限分配给部分受信任的代码,否则它将无法访问不可访问的成员。成员可访问性不是编译时唯一的功能。这是在运行时也强制执行的安全功能,但如果您授予某人
FullTrust
权限,则他们可以绕过它。IFoo的直接成员不能使用内部关键字实现,您将获得编译错误。
var myClassObj = new MyClass<string>();
(myClassObj as IList<string>).Add("Haha, gotcha!");