版本之间的接口的改变 - 如何管理? [英] Interface change between versions - how to manage?

查看:114
本文介绍了版本之间的接口的改变 - 如何管理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我们钻进一个客户网站相当不愉快的咸菜。客户端有大约100工作站上,我们部署了我们的产品的MyApp的1.0.0版本。



现在,的产品确实的事情之一是它加载了一个加载项(称之为为myplugin,它首先查找在中央服务器上,以查看是否有更新的版本,如果是然后将其复制在本地文件,然后将它加载了外接使用的Assembly.Load 并调用某些已知的接口,这已经连续数月运作良好。



然后客户希望在某些机器上安装我们的产品V1.0.1(但不是全部),这与为myplugin的一个新的和更新的版本来了。



但随后而来的问题。有一个共享DLL,它是由两个MyApp的和为myplugin引用,称为MYDLL,其中有一个方法 MyClass.MyMethod 。V1.0.0和V1.0.1之间,签名 MyClass.MyMethod 改变(增加了一个参数),现在为myplugin的新版本会导致V1.0.0客户端应用程序崩溃:




找不到方法:MyClass.MyMethod(System.String)




客户有针对性地做不希望在所有客户站部署V1.0.1,在于被包含在1.0.1修复只有几个工作站是必要的,而且也没有必要以推广到所有的客户端。可悲的是,我们使用ClickOnce或其他大规模部署公用事业,所以推出了1.0.1版将是一个痛苦的,否则不必要的运动是不是(还)。



有一些在为myplugin编写代码,以便它会工作得很好,不管它的处理MYDLL V1.0.0或V1.0.1的方式吗? ?也许有使用反射来查看它是否存在一个预期的接口探测,实际调用它之前的一些方法



编辑:我也要何况 - 我们有一些很紧质量保证程序。由于V1.0.1已通过QA已经正式发布,我们是不允许做出MyApp的或MYDLL任何更改。我们有运动的唯一的自由就是改变为myplugin,这是专门为这个客户所撰写的自定义代码。


解决方案

我已经提取从应用程序的代码前,我写了一段时间,并去掉了一些零件|
很多东西都在这里假定:




  1. MYDLL.DLL的位置是当前目录

  2. 来获得反射信息的命名空间是MyDll.MyClass

  3. 类有没有参数的构造

  4. 您不希望返回值





 使用的System.Reflection; 

私人无效CallPluginMethod(字符串参数)
{
//是MYDLL.DLL在当前目录?
//也许这是更好地调用Assembly.GetExecutingAssembly()的位置,但......
串libToCheck = Path.Combine(Environment.CurrentDirectoryMYDLL.DLL);
大会提出= Assembly.LoadFile(libToCheck);
串typeAssembly =MyDll.MyClass; //这是正确的命名空间?
型C = a.GetType(typeAssembly);

//获取公共非静态方法
的MethodInfo [] = miList所有c.GetMethods方法的相关信息(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
//搜索所需的一(可以使用LINQ进行优化?)
的foreach(MethodInfo的MI在miList)
{
如果(mi.Name ==的MyMethod)
{
//创建一个MyClass的对象,假设它有一个空的构造
ConstructorInfo clsConstructor = c.GetConstructor(Type.EmptyTypes);
对象MyClass的= clsConstructor.Invoke(新的对象[] {});

//检查有多少参数是必需的
如果(mi.GetParameters()。长度== 1)
//调用新的接口
mi.Invoke (MyClass的,新的对象[] {参数});
,否则
//调用旧的接口或发出异常
mi.Invoke(MyClass的,NULL);
中断;
}
}
}



我们做什么在这里:




  1. 加载动态库并提取类型 MyClass的

  2. 使用的种类,要求的反射子系统的列表的MethodInfo 出现在该类型。

  3. 检查每方法名找到所需要的。

  4. 当方法发现生成的类型的实例。

  5. 获得预期的参数的数量方法。

  6. 根据参数的个数调用使用调用


  7. Here's a rather unpleasant pickle that we got into on a client site. The client has about 100 workstations, on which we deployed version 1.0.0 of our product "MyApp".

    Now, one of the things the product does is it loads up an add-in (call it "MyPlugIn", which it first looks for on a central server to see if there's a newer version, and if it is then it copies that file locally, then it loads up the add-in using Assembly.Load and invokes a certain known interface. This has been working well for several months.

    Then the client wanted to install v1.0.1 of our product on some machines (but not all). That came with a new and updated version of MyPlugIn.

    But then came the problem. There's a shared DLL, which is referenced by both MyApp and MyPlugIn, called MyDLL, which has a method MyClass.MyMethod. Between v1.0.0 and v1.0.1, the signature of MyClass.MyMethod changed (a parameter was added). And now the new version of MyPlugIn causes the v1.0.0 client apps to crash:

    Method not found: MyClass.MyMethod(System.String)

    The client pointedly does not want to deploy v1.0.1 on all client stations, being that the fix that was included in v1.0.1 was necessary only for a few workstations, and there is no need to roll it out to all clients. Sadly, we are not (yet) using ClickOnce or other mass-deployment utilities, so rolling out v1.0.1 will be a painful and otherwise unnecessary exercise.

    Is there some way of writing the code in MyPlugin so that it will work equally well, irrespective of whether it's dealing with MyDLL v1.0.0 or v1.0.1? Perhaps there's some way of probing for an expected interface using reflection to see if it exists, before actually calling it?

    EDIT: I should also mention - we have some pretty tight QA procedures. Since v1.0.1 has been officially released by QA, we are not allowed to make any changes to MyApp or MyDLL. The only freedom of movement we have is to change MyPlugin, which is custom code written specifically for this customer.

    解决方案

    I have extracted this code from an application I wrote some time ago and removed some parts.
    Many things are assumed here:

    1. Location of MyDll.dll is the current directory
    2. The Namespace to get reflection info is "MyDll.MyClass"
    3. The class has a constructor without parameters.
    4. You don't expect a return value

    using System.Reflection;
    
    private void CallPluginMethod(string param)
    {
         // Is MyDLL.Dll in current directory ??? 
         // Probably it's better to call Assembly.GetExecutingAssembly().Location but....
         string libToCheck = Path.Combine(Environment.CurrentDirectory, "MyDLL.dll");  
         Assembly a = Assembly.LoadFile(libToCheck);
         string typeAssembly = "MyDll.MyClass"; // Is this namespace correct ???
         Type c = a.GetType(typeAssembly);
    
         // Get all method infos for public non static methods 
         MethodInfo[] miList = c.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
         // Search the one required  (could be optimized with Linq?)
         foreach(MethodInfo mi in miList)
         {
             if(mi.Name == "MyMethod")
             {
                 // Create a MyClass object supposing it has an empty constructor
                 ConstructorInfo clsConstructor = c.GetConstructor(Type.EmptyTypes);
                 object myClass = clsConstructor.Invoke(new object[]{});
    
                 // check how many parameters are required
                 if(mi.GetParameters().Length == 1)
                     // call the new interface 
                     mi.Invoke(myClass, new object[]{param});
                 else 
                     // call the old interface or give out an exception
                     mi.Invoke(myClass, null);
                 break;
             }
         }
    }
    

    What we do here:

    1. Load dynamically the library and extract the type of MyClass.
    2. Using the type, ask to the reflection subsystem the list of MethodInfo present in that type.
    3. Check every method name to find the required one.
    4. When the method is found build an instance of the type.
    5. Get the number of parameters expected by the method.
    6. Depending on the number of parameters call the right version using Invoke.

    这篇关于版本之间的接口的改变 - 如何管理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆