C# 程序集别名

C# 程序集别名

1. extern alias

虽然开发项目时很少遇到两个相同完全限定名的类型(命名空间.类名),但偶然还是会遇到这种情况。比如,在某些情况下,项目中必须引用某程序集的新旧多个版本。 通过使用外部程序集别名,可以将来自每个程序集的命名空间包装在由别名命名的根级别命名空间中,从而使这些命名空间可以在同一文件中使用。

MSDN官方解释:

You might have to reference two versions of assemblies that have the same fully-qualified type names. For example, you might have to use two or more versions of an assembly in the same application. By using an external assembly alias, the namespaces from each assembly can be wrapped inside root-level namespaces named by the alias, which enables them to be used in the same file.

注意这和单独extern 关键字来使用非托管代码(C++d等)不是一回事。

要引用两个具有相同完全限定类型名的程序集, 例如:

extern alias GridV1;

extern alias GridV2;

每一个外部别名声明都引入一个额外的根级别命名空间,它与全局命名空间global平行,而不是在全局命名空间内。 因此,通过使用根源于相应命名空间别名的完全限定名,可以无歧义地引用每个程序集的类型。在程序中,GridV1::Grid 是来自 grid.dll 的网格控件,而 GridV2::Grid 是来自 grid20.dll 的网格控件。

如下图所示,一般所有程序集的别名都默认是global,将别名修改为其它名称就可以extern alias 方式使用了。extern alias 一般需要写在所有using 程序集名语句之前。

extern alias V2;
using System;

Visual Studio中可以给一个程序集起多个别名,用逗号隔开,所以下图中属性名显示的是Aliases而不是Alias。

2. 实际测试

新建一个解决方案,包括三个项目: 2个有相同命名空间的类库项目,1个控制台测试项目。

 

ClassLibraryV1项目中Cat类和Puppy类如下:

using System;

namespace ClassLibrary
{
    public class Cat
    {
        public void Meow()
        {
            Console.WriteLine("A cat meow1.");
        }
    }
}
using System;

namespace ClassLibrary
{
    public class Puppy
    {
        public void Bark()
        {
            Console.WriteLine("A puppy bark.");
        }
    }
}

ClassLibraryV2项目中Cat类和Puppy类如下:

using System;

namespace ClassLibrary
{
    public class Cat
    {
        public void Meow()
        {
            Console.WriteLine("A cat meow2.");
        }
    }
}
using System;

namespace ClassLibrary
{
    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("A dog bark.");
        }
    }
}

然后TestLibrary项目引用ClassLibraryV1和ClassLibraryV2。

1)测试只使用完全限定名不同的类

static void Main(string[] args)
 {
        var puppy=new  ClassLibrary.Puppy();
        puppy.Bark();

         var dog=new ClassLibrary.Dog();
         dog.Bark();

         Console.ReadKey();
}

运行正常(这种情况是最普通的,虽然程序集的命名空间相同,但是类型不同)

2)测试使用完全限定名相同的类

首先,编译器会报错:无法判断有歧义的类型。

这时,就需要更改程序集别名,如将ClassLibraryV1的别名从global改为V1,

extern alias V1;
using System;

namespace TestLibrary
{
    class Program
    {
        static void Main(string[] args)
        {
            var cat1 = new V1::ClassLibrary.Cat();
            cat1.Meow();
            var cat2 = new ClassLibrary.Cat();
            cat2.Meow();

            var puppy = new V1::ClassLibrary.Puppy();
            puppy.Bark();
            var dog=new ClassLibrary.Dog();
            dog.Bark();

            Console.ReadKey();
        }
    }
}

运行结果:

3. 项目扩展感悟

遇到一个改造程序,程序中大部分开发的代码引用的是一家控件厂商的最新版本(V15)。但是,程序引用的一个A.dll是基于V13开发的(即A.dll用到了V13的某个类型)。首先,如果不引用V13到程序中,则编译不通过(提示找不到某类型);然后引用V13后,也编译报错(很多类型存在歧义)。

最后解决方式是把V13的程序集别名改为非global(任意名都可以),程序中也没有地方需要用extern alias,编译成功后运行正常。

为什么没有用到extern alias?

猜测是因为该程序开发中并没有直接用到V13的类型,只是引用的A.dll用到了V13; 程序运行时自身用到的V15程序集正常加载,A.dll也加载入内存,A.dll加载时根据其CLR manifest描述来加载V13程序集。具体机制还需要深入学习下CLR等相关知识。

转载请注明出处:https://www.cnblogs.com/lichu-lc/p/12863586.html

参考:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias

posted @ 2020-05-10 15:58  double蠢  阅读(1601)  评论(0编辑  收藏  举报