将公共接口实现限制为仅供内部使用

时间:2017-10-29 19:21:03

标签: c# inheritance interface internal

我有一个继承/ 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只能通过内部接口实现此接口

我是否应该使用不同的模式,如果我希望我的类实现公共接口功能,那只应该在内部可用?

1 个答案:

答案 0 :(得分:1)

  

我原本以为编译器会抱怨没有办法将myClassObj投射到IList<string>

编译器无法做到这一点。除非在非常有限的情况下,编译器会依次对待显式的强制转换和转换,并假设自从您编写它以来,就意味着它。在编译器总是在运行时失败的情况下编写代码并不难,即使编译器允许它,即使您可以查看代码并看到它总是会失败。

要了解原因,请考虑您的对象始终可以由object类型的变量引用。当发生这种情况时,编译器不知道对象的声明实现。它不能阻止代码中的强制转换,即使已知强制转换是非法的。

当然,在运行时,唯一重要的是对象实际是否实现了接口。所以演员甚至都不是非法的。显式接口实现不会隐藏接口。它只是强制要求除了通过该接口类型的表达式之外不能使用该实现。它根本不是控制可访问性的手段。

如果您不希望外部代码在外部代码可以访问的对象中看到您的IList<T>实现,那么您必须实际隐藏该代码。唯一的方法是更改​​您的设计,以便您的对象 IList<T>而不是 IList<T>(即组合vs.继承),IList<T>只能访问您想要的代码(例如,由标记为internal的属性公开)。

请记住,即便如此,可访问性主要是编译时安全功能。无论可访问性如何,在完全信任环境中(即在绝大多数托管代码执行的上下文中)的反射将始终允许访问对该对象具有访问权限的任何代码。为了鼓励正确使用您的类型,限制访问是一件好事,但它本身并不是一个安全功能(尽管它可以与之结合使用)。