Как я могу выполнить горячую замену DLL, на которые ссылаются, без перекомпиляции Решения в VS2008? - PullRequest
6 голосов
/ 19 мая 2011

В нашем решении есть ссылка на DLL, которая используется для связи с некоторыми аппаратными средствами через Ethernet. Мы создали вторую DLL-библиотеку, которую можно использовать для моделирования оборудования, чтобы нашим разработчикам не требовалось указывать это оборудование на каждом из их рабочих мест.

Программное обеспечение не должно знать, использует ли оно реальное оборудование или симулятор. Как мы можем поменять местами ссылки без необходимости перекомпилировать решение?

Можем ли мы просто назвать обе ссылки одинаковыми и просто зарегистрировать / отменить регистрацию правильной библиотеки DLL, на которую мы хотим сослаться?

[Update] Примечание. Первая DLL - это сторонняя DLL, к которой у нас тоже нет доступа. Вторая DLL была создана нами в C ++. Наше приложение написано на C #.

Ответы [ 4 ]

2 голосов
/ 19 мая 2011

MEF (Managed Extensibility Framework) позволяет действительно легко делать подобные вещи. Просто убедитесь, что ваши реальные и фиктивные интерфейсы экспортируют один и тот же контракт и используют композицию MEF, чтобы ввести нужную версию.

Вот простой пример того, как его использовать.

2 голосов
/ 19 мая 2011

Сделайте так, чтобы обе библиотеки DLL реализовывали общий интерфейс (ICommunicateToYourHardware) и закодировали приложение для обнаружения библиотеки DLL с помощью отражения, а не по ссылке.

По запросу с добавлением образца

Интерфейс в этом примере называется IAuthenticate, но вы можете использовать любой интерфейс вместо него. В этом случае я на самом деле ищу любое число классов IAuthenticate. В вашем случае, если разные библиотеки DLL размещены в одном и том же относительном пути, одна и та же компиляция будет загружать разные библиотеки DLL.

 // We need a container for the DLL files that we find and then a container for the instances of 
    // the plug ins created from the dlls. In this test we are only really looking for One such plug in
    // but I prefer to use collections for such things as it allows for a more scalable design. This technique
    // works for 1, 100, or more plugins and/or methods.
    private List<string> _DLLS;
    private List<iAuthenticate> _PlugIns;

    private int LoadPlugIns(string Path)
    {
        /// Within the designated Path (and in all subdirectories) locate all .dll files and put the path 
        /// to these files in a collection.
        GetDLLS(Path);
        foreach (string dirName in Directory.GetDirectories(Path))
        {
            LoadPlugIns(dirName);
        }

        // For each .dll file, inspect it (using reflection) to determine if it is of the iAuthenticate Type
        // if it is, create and instance of the object and store it in a collection, and assign a delegate to 
        // invoke its Authenticate method from the host application.
        foreach (string DLL in _DLLS)

        {
            Assembly myAssembly = Assembly.LoadFrom(DLL);
            Type[] Types = myAssembly.GetTypes();
            foreach (Type myType in Types)
            {
                Type T = myType.GetInterface("iAuthenticate");
               if (T != null)
                {
                    if (_PlugIns == null) { _PlugIns = new List<iAuthenticate>(); }
                    _PlugIns.Add((iAuthenticate)myAssembly.CreateInstance(myType.FullName));
                }
            }
            foreach (iAuthenticate iAuth in _PlugIns)
            {
                this.Authorize += iAuth.Authenticate;
            }
        }
        return _PlugIns.Count;
   }

    private void GetDLLS(string Path)
    {
        if (_DLLS == null){_DLLS = new List<string>();}
        foreach (string filename in Directory.GetFiles(Path, "*.dll")) 
        {
            _DLLS.Add(filename);
        }
    }

как только у нас есть набор ссылок через отражение, мы можем вызвать его методы следующим образом:

    private void btnLogon_Click(object sender, EventArgs e)
    {
        try
        {
            if (Authorize.Invoke(txtUsername.Text, txtPassword.Text, txtPath.Text))
            {
                this.BackgroundImage = TelefloraDemo.Properties.Resources._189469;
                this.pnlLogon.Visible = false;
                MessageBox.Show("You have Logged On!");
            }
        }
        catch (AuthenticationException aex)
        {
            DemoCode.LogException(aex);
            MessageBox.Show(aex.ToString());
        }
        catch (Exception ex)
        {
            DemoCode.LogException(ex);
            MessageBox.Show("No Authenticator");
        }

    }

    public delegate bool Authenticate(string Username,string Password,string Path);
    public event Authenticate Authorize;

Теперь, очевидно, ваш пробег может отличаться, но это должно привести вас к успешной трассе. (Да, есть другие способы, мне нравится этот ..)

0 голосов
/ 19 мая 2011

Ссылка на оба и использование фабричного класса для создания соответствующих интерфейсов. Затем вы можете использовать какой-то внешний механизм: файл конфигурации, запись реестра, имя машины, идентификатор сборки и т. Д., Чтобы заставить фабрику выдавать правильный интерфейс.

0 голосов
/ 19 мая 2011

Это от MSDN

Вы можете перенаправить ссылку привязки сборки на другую версию сборки, используя записи в файлах конфигурации приложения или машины.Вы можете перенаправить ссылки на сборки .NET Framework, сторонние сборки или сборки вашего собственного приложения.Каждая версия .NET Framework имеет файл конфигурации компьютера, и любая информация о перенаправлении в этом файле влияет на все приложения, работающие в этой версии .NET Framework.

...