具有可选的依赖关系处理(C#)(Dealing with optional dependencies

2019-08-06 01:41发布

我们有任选TFS集成的应用,但是作为集成是可选的我显然不希望将所有的机器需要的TFS组件的要求

我该怎么办?

  1. 它是确定由我来引用TFS库在我的主要组件和公正,确保当我使用TFS集成,我只能引用TFS相关的对象。
  2. 可替换地,更安全的选择将是引用TFS库在一些单独的“TFSWrapper”组件:

    一个。 它是那么好,我来(只要我小心再次约我所说的)直接引用该程序集

    湾 我应该改为公开一组接口为我TFSWrapper组装来实现,然后使用反射在需要时实例化的对象。

1似乎有风险的我,在另一面2B似乎过了顶 - 我基本上可以建立一个插件系统。

当然,必须有一个简单的方法。

Answer 1:

最安全的方式(即不使你的应用程序中的错误,最简单的方法)可能如下。

让这些抽象的TFS的使用,例如接口:

interface ITfs
{
  bool checkout(string filename);
}

写它实现了使用TFS此接口的类:

class Tfs : ITfs
{
  public bool checkout(string filename)
  {
    ... code here which uses the TFS assembly ...
  }
}

写它实现了在不使用TFS这个接口另一个类:

class NoTfs : ITfs
{
  public bool checkout(string filename)
  {
    //TFS not installed so checking out is impossible
    return false;
  }
}

有一个单身的地方:

static class TfsFactory
{
  public static ITfs instance;

  static TfsFactory()
  {
    ... code here to set the instance
    either to an instance of the Tfs class
    or to an instance of the NoTfs class ...
  }
}

现在,只有一个地方一个需要小心(即TfsFactory构造函数); 你的代码的其余部分可以调用您TfsFactory.instance的ITFS方法不知道是否安装TFS。


要回答以下最近的评论:

根据我的测试(我不知道这是否是“定义的行为”),一个例外是当(只要)抛出调用它取决于缺少的组件的方法。 因此,在汇编封装代码,其中 - 依赖 - 上的缺失装配在至少一个单独的方法(或单独的一类)是很重要的。

例如,如果通话组件缺少以下将不会加载:

using System;
using OptionalLibrary;

namespace TestReferences
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            if (args.Length > 0 && args[0] == "1") {
                Talk talk = new Talk();
                Console.WriteLine(talk.sayHello() + " " + talk.sayWorld() + "!");
            } else {
                Console.WriteLine("2 Hello World!");
            }
        }
    }
}

以下将加载:

using System;
using OptionalLibrary;

namespace TestReferences
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            if (args.Length > 0 && args[0] == "1") {
                foo();
            } else {
                Console.WriteLine("2 Hello World!");
            }
        }

        static void foo()
        {
            Talk talk = new Talk();
            Console.WriteLine(talk.sayHello() + " " + talk.sayWorld() + "!");
        }
    }
}

这些测试结果(在Windows上使用MSVC#2010和.NET):

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>TestReferences.exe
2 Hello World!

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>TestReferences.exe 1

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'OptionalLibrary, Version=1.0.0.0,
 Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at TestReferences.MainClass.foo()
   at TestReferences.MainClass.Main(String[] args) in C:\github\TestReferences\TestReferences\TestReferences\Program.cs:
line 11

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>


Answer 2:

你可能看托管扩展性框架 (MEF)。



Answer 3:

A“插件”的概念可能是要走的路,它也可以让你(后下)扩展您的应用程序,如果需要与其他产品比TFS工作。 选项2a将是多么的“冒险”(当链接文件丢失故障)的选项1。

您可以组装与您的特定用途所需的接口,以及来自您的应用程序和“TFS插件”引用该组件。 后者则提供您接口的实现,并使用TFS来执行操作。 该应用程序可以动态加载的组件,并创建所需要的插件类型的实例(通过激活等)和铸造的那些情况下,以您的接口。

事实上,如果你让那些类型继承MarshalByRef ,你甚至可以将其加载到另一个AppDomain中 ,从而使你的插件的完全分离,也使他们卸。



文章来源: Dealing with optional dependencies (C#)