【问题标题】:Alternatives to the "using" directive keyword in C#?C# 中“使用”指令关键字的替代方案?
【发布时间】:2009-09-10 11:39:02
【问题描述】:

我刚看完 NDC 的 Bob Martin 的一集,他说页面顶部的 C# 中的“使用”指令很糟糕,因为它们在组件之间创建/暗示了紧密耦合。

有什么方法可以在不添加项目引用和 using 语句的情况下使用外部 .dll?

我记得 V6 曾经让您通过 ProgId 的字符串创建一个对象——我不确定这是我正在寻找的技术,但它是一个不需要项目参考的语言示例使用 dll。

编辑:Here is a link to the conference。抱歉,演讲中没有准确的报价或分钟,我是凭记忆进行的。

【问题讨论】:

  • 他真的这么说,还是你对他说的话的理解?
  • 这个链接会很有帮助。我想听听他到底说了什么。
  • 为了避免混淆,微软将其称为 using “指令”。 using 语句(关键字)通常是指在方法内部使用的语句,以自动调用资源上的 Dispose。

标签: c# coupling decoupling


【解决方案1】:

我相信 Bob Martin 实际上指的是早期绑定和后期绑定。

在 .NET 中,后期绑定可以通过反射实现,更具体地说是 Activator 类,它允许使用文件名或程序集名称在外部程序集中创建类型。

通常,using 指令(而不是 using 语句)与直接引用外部程序集齐头并进。 IE。您添加对程序集的引用,然后添加 using 指令以避免在使用外部类型时需要键入完整的命名空间层次结构。

因此,如果您发现代码顶部有大量 using 指令,则可能是您直接引用了许多其他类型,从而增加了代码对这些类型的耦合/依赖性。

我猜这就是 Bob 说他们不好的原因。 “这真的很糟糕吗?”这个问题的答案。是一个非常主观的和上下文相关的。

不过,总的来说,组件的解耦几乎总是一个很好的目标,即设计软件的目标。这是因为它允许您更改系统的某些部分,而对系统的其余部分的影响最小。读过一两本 Bob Martins 的书,我想这就是他的意思。

【讨论】:

    【解决方案2】:

    不好的不是 using 语句本身 - 而是如果你得到 太多 它们。

    using System; 之类的语句本身很少有问题,但如果您在同一个代码文件中有很多(我会说超过 3-6 个,具体取决于哪些),它可能是一个 表示紧耦合

    您也可以将类似的经验法则应用于项目本身的引用数量。

    紧密耦合的解决方案是接口编程和依赖注入(DI)。

    您可以从 VB 中记住的 ProgId 做事方式就是 COM 的实际操作。本质上,您使用该 ProgId 来获取对实现所需接口的实例的引用。缺点是这只在 COM 对象被普遍注册时才有效。还记得 dll 地狱吗?

    您仍然可以使用某些风格的 DI 应用相同的原理,只是现在接口是 .NET 类型且未在 IDL 中定义,并且您需要某种 DI 容器来提供具体实现。

    【讨论】:

    • 我会写这个“它可能表示紧密耦合”而不是“如果可能是一个表示紧密耦合
    • @Vinko Vrsalovic:不,我不同意:如果你有 20 个 using 语句,那绝对是紧密耦合的指示
    • 然后这样说:“这是紧密耦合的指示
    • @Vinko Vrsalovic:哦,但我也想强调一下紧耦合这个词,因为我相信这实际上是问题的症结所在。
    【解决方案3】:

    using 只是命名空间的快捷方式,它们不是对外部文件的引用。因此,这是没有意义的。

    无论如何,可以做的是拥有一个接口 DLL(一个只有接口的 DLL),这样您就可以动态加载和使用不同的程序集并创建可以转换为众所周知的接口的类型(通过反射)。这是在保持强类型语言和早期绑定优势的同时放松外部引用的正确方法。

    查看 AssemblyAppDomain 类以加载程序集,查看 Activator 以按名称创建类型实例。

    【讨论】:

    • 同意。这个说using 声明不好的家伙显然不知道他在说什么。
    • @Noldorin:Robert C. Martin 不知道他在说什么?!
    • 或者他被误解了。谁是错或谁错并不重要,因为“收到的信息”没有意义。
    【解决方案4】:

    你可以使用反射:

    // Load the assembly
    Assembly assembly = Assembly.LoadFrom(@"c:\path\Tools.dll");
    // Select a type
    Type type = assembly.GetType("Tools.Utility");
    // invoke a method on this type
    type.InvokeMember("SomeMethod", BindingFlags.Static, null, null, new object[0]);
    

    【讨论】:

    • 这种调用类型称为后期绑定,它不仅速度慢而且很容易出错,而且在 C# 等不支持开箱即用的后期绑定的语言中也非常麻烦(例如通过编译器魔术)。如果可能的话,我会避免这种方法。
    • 老实说,最好为这种事情使用 DI 框架。也更适合菜鸟。
    【解决方案5】:

    您可以通过反思来做您所指的事情。您可以在运行时加载程序集,并通过它反映以获取类等并动态调用它们。

    就个人而言,我不会这样做以避免耦合。对我来说,这是对反射的不好使用,我更愿意将它添加到项目中并引用它,除非有特定的理由不这样做。反射增加了系统的开销,并且您没有获得编译时安全的优势。

    【讨论】:

    • 此外,这种“技术”不会避免耦合。您的代码与外部 DLL 的耦合并没有减少,因为您正在动态调用它 - 如果 DLL 不存在,您的代码将无法工作。
    • 如果您有接口程序集并动态加载具有接口的对象,它确实会减少耦合。依赖注入也是一个不错的方法。
    • @Kenny:在这种情况下你是完全正确的。我更想说的是,如果你只是删除一个引用并动态加载它,你并没有改善这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 2015-07-31
    相关资源
    最近更新 更多