我可以防止通过 public API 公开第 3 方库的 'details' 吗?

Can I prevent exposing 'details' of 3rd party library through public API?

我正在创建一个库,它是第 3 方库的包装和扩展。有没有办法防止无意中暴露 3rd 方库?或者至少得到一个警告?我不希望我的图书馆的用户引用(依赖)第 3 方图书馆。

例如可以这样做:

public class MyLibraryClass
{
    public void Use3rdParty(3rdPartyClass c)
    {
        // Do something...
    }
}

我知道将方法标记为内部方法可以解决问题。让我恼火的是,我犯了错误,暴露了一些本应是内部的方法。我希望以后避免这种情况。

此外,我想问一下从第 3 方进行 public 隐式转换是否安全 class:

public class MyLibraryClass
{
    public static implicit operator MyLibraryClass(3rdPartyClass c)
    {
        // Conversion...
    }
}

操作符必须被定义为静态的并且public所以这个方法不能是内部的。根据我的想法,它应该是安全的,因为在我的库之外,用户应该看不到这种转换方法,因此甚至无法尝试这种转换。

总的来说,我不担心安全问题,所以我不介意通过反射用户可以访问 'anything'。更重要的是让 API 干净,不要混淆用户。

我正在使用 VS 2010 和 .NET 4.0。

编辑: 总结并澄清一下,我的问题是您可能无意中(意外地)公开了一些第 3 方库的详细信息,并且您没有收到编译器的任何警告或任何东西。我正在寻找一些方法来告诉编译器程序集应该只在具有内部或较低访问权限的地方使用。

以后我会考虑使用 ViewModel 或 DTO(数据传输对象)来隐藏第 3 方库的 implementation/detail。这将提供一个您可以完全控制的界面,该界面独立于第 3 方 API 的任何实现。

这样,如果你切换到另一个库,你不必重写你的 API 来匹配你正在做的工作的任何 new/switched/thrown 自己的依赖关系,它是从你的 API 消费者,只要您不在新的 ViewModel 或 DTO 中公开这些细节。

我认为,如果您有隐式转换运算符,Visual Studio 会询问使用您的库的任何人,他们有对这些运算符中引用的任何类型的引用。如果您有任何类型在第 3 方库中实现接口,也是一样的。

您可以使用 Roslyn 来做这类事情,但听起来您使用的是 Visual Studio 的旧版本,所以这可能不是一个选项。

另一种选择是使用反射从第 3 方库构建类型列表,然后使用反射扫描库中 public 类型的 public/protected 成员以查看是否他们中的任何一个都使用这些类型。将其添加为 "unit" 测试或作为构建过程的一部分自动运行的东西。

您可以使用以下方法获取程序集中的类型列表:

Type[] types = typeof(SomeTypeInAnAssembly).Assembly.GetTypes()

使用第 3 方程序集中的类型列表,然后您可以遍历程序集中的类型并检查每个构造函数 (type.GetConstructors)、每个 属性 (type.GetProperties ),每个字段 (type.GetFields)。这些方法采用 BindingFlags 值,您将要指定 public 和非 public、instance 和 static 以获取所有方法。然后,您将要过滤 public(IsPublic 属性)或受保护(MemberInfo 结构上的 IsFamily 属性)的内容。检查 methods/constructors 和 return 类型的参数类型。

让我们从观察开始:

I don't want users of my library to reference (depend on) the 3rd party library. …

public void Use3rdParty(3rdPartyClass c)

您只是强迫 API 的用户依赖第三方库。 (如果没有准备好传入的第三方库对象,他们就无法调用您的 API。)

话虽如此,好的解决方案取决于你自己的库主要是扩展第三方库,还是主要使用第三方库作为私有实现细节

你的库主要扩展了第三方库:

我不会进一步讨论,因为我不确定你的问题在这种情况下是否有意义:如果你的库扩展了第三方库,那么它的用户应该使用第三方库已经,因此您不需要首先隐藏它。

您的库使用第三方库主要作为私有实现细节:

那你应该完全把第三方库隐藏在你自己的API后面。这意味着第三方库的类型可能根本不会出现在您自己的 API 的方法签名中。

一个好方法(伴随着一些小的开销)是将所有第三方库的类型(或者至少是那些你会以其他方式公开的类型)包装在你自己的包装器中 类:

namespace ThirdPartyLibrary
{
    public class ThirdPartyLibrary.Quux
    {
        public void Foo() { … }
        …
    }
}

namespace YourLibrary
{
    public sealed class Quux  // has same methods as the third-party library's type
    {
        private readonly ThirdPartyLibrary.Quux wrapped;
        …
        public Foo() { wrapped.Foo(); }  // forward calls to the underlying type
    }
}

然后根据这些包装器 类 写下你的库 public API 的剩余部分(顺便说一句,这也是你的 API 的一部分):

namespace YourLibrary
{
    public class Frobbler
    {
        public void Frobble(Quux c)
        {                // ^^^^
            …            // your wrapper class, not the third-party original 
        }
    }
}

(此外,将第三方 DLL 合并到您自己的(,或使用 ILMerge 等工具)可能是个好主意,这样您的库就无法在没有只有它可能依赖的 DLL。)