随笔- 235  评论- 242  文章- 0 

Assembly的load, loadfrom, loadfile方法总结

经常弄混这三个方法, 参考了一堆帖子, 总结如下:


一.Load方法
1.Load(AssemblyName) 在给定程序集的 AssemblyName 的情况下,加载程序集。
例1: TestLib.LzdTest lzdTeset = (TestLib.LzdTest)Assembly.Load("TestLib").CreateInstance("TestLib.LzdTest");


用Reflector查看源码如下:
public static Assembly Load(AssemblyName assemblyRef)
{
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
    return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, ref lookForMyCaller, false, false);
}

 
2.Load(AssemblyString) 通过给定程序集的长格式名称加载程序集。
例2: TestLib.LzdTest lzdTeset = (TestLib.LzdTest)Assembly.Load("TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").CreateInstance("TestLib.LzdTest");


用Reflector查看源码如下:
public static Assembly Load(string assemblyString)
{
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
    return RuntimeAssembly.InternalLoad(assemblyString, null, ref lookForMyCaller, false);
}


[MethodImpl(MethodImplOptions.NoInlining), SecurityCritical]
internal static RuntimeAssembly InternalLoad(string assemblyString, Evidence assemblySecurity, ref StackCrawlMark stackMark, bool forIntrospection)
{
    if (assemblyString == null)
    {
        throw new ArgumentNullException("assemblyString");
    }
    if ((assemblyString.Length == 0) || (assemblyString[0] == '\0'))
    {
        throw new ArgumentException(Environment.GetResourceString("Format_StringZeroLength"));
    }
    AssemblyName assemblyRef = new AssemblyName();
    RuntimeAssembly assembly = null;
    assemblyRef.Name = assemblyString;
    if (assemblyRef.nInit(out assembly, forIntrospection, true) == -2146234297)
    {
        return assembly;
    }
    return InternalLoadAssemblyName(assemblyRef, assemblySecurity, ref stackMark, forIntrospection, false);
}

总结: 使用Load方法加载程序集,特别是强命名程序集,能在程序集上应用安全和部署策略,一般情况下都应该优先使用这个方法。


二.LoadFrom (已知程序集的文件名或路径,加载程序集。)
例3: TestLib.LzdTest lzdTeset = (TestLib.LzdTest)Assembly.LoadFrom("D:\\workspace\\LatestWebTestSite\\TestLib.dll").CreateInstance("TestLib.LzdTest");


用Reflector查看源码如下:
public static Assembly LoadFrom(string assemblyFile)
{
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
    return RuntimeAssembly.InternalLoadFrom(assemblyFile, null, null, AssemblyHashAlgorithm.None, false, false, ref lookForMyCaller);
}

 
[MethodImpl(MethodImplOptions.NoInlining), SecurityCritical]
internal static RuntimeAssembly InternalLoadFrom(string assemblyFile, Evidence securityEvidence, byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, bool forIntrospection, bool suppressSecurityChecks, ref StackCrawlMark stackMark)
{
    if (assemblyFile == null)
    {
        throw new ArgumentNullException("assemblyFile");
    }
    if ((securityEvidence != null) && !AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_RequiresCasPolicyImplicit"));
    }
    AssemblyName assemblyRef = new AssemblyName();
    assemblyRef.CodeBase = assemblyFile;
    assemblyRef.SetHashControl(hashValue, hashAlgorithm);
    return InternalLoadAssemblyName(assemblyRef, securityEvidence, ref stackMark, forIntrospection, suppressSecurityChecks);
}

MSDN: LoadFrom 方法具有以下缺点。请考虑改用 Load。
1.如果已加载一个具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 仍返回已加载的程序集。
2.如果用 LoadFrom 加载一个程序集,随后加载上下文中的一个程序集尝试加载具有相同显示名称的程序集,则加载尝试将失败。对程序集进行反序列化时,可能发生这种情况。

总结: LoadFrom只能用于加载不同标识的程序集, 也就是唯一的程序集, 不能用于加载标识相同但路径不同的程序集。

从例子1,2,3的源代码中可以看出来, 三者归根结都是调用RuntimeAssembly.InternalLoadAssemblyName()方法的.

 

三.LoadFile (加载指定路径上的程序集文件的内容。)
例4: TestLib.LzdTest lzdTeset = (TestLib.LzdTest)Assembly.LoadFrom("D:\\workspace\\LatestWebTestSite\\TestLib.dll").CreateInstance("TestLib.LzdTest");

用Reflector查看源码如下:
public static Assembly LoadFile(string path)
{
    new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, path).Demand();
    return RuntimeAssembly.nLoadFile(path, null);
}

[MethodImpl(MethodImplOptions.InternalCall), SecurityCritical]
internal static extern RuntimeAssembly nLoadFile(string path, Evidence evidence);
 
extern 修饰符用于声明 由程序集外部实现的成员函数经常用于系统API函数的调用(通过 DllImport )。
注意,和DllImport一 起使用时要加上 static 修饰符也可以用于对于同一程序集不同版本组件的调用(用 extern 声明别名) 不能与 abstract 修饰符同时使用 。


这个方法也不能加载同标识不同路径的程序集,否则也提示错误:

[A]TestLib.LzdTest cannot be cast to [B]TestLib.LzdTest. Type A originates from 'TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither' at location 'D:\workspace\LatestWebTestSite\LatestWebTestSite\bin\TestLib.dll'. Type B originates from 'TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\25a52d02\3d6c3f29\assembly\dl3\c37d3dd1\72d288f9_135bcc01\TestLib.DLL'.

 

总结: 这个方法是从指定的文件来加载程序集,它是调用外部的API实现的加载方式,和上面Load,LoadFrom方法的不同之处是这个方法不会加载此程序集引用的其他程序集,也就是不会加载程序的依赖项。

 

参考帖子: http://blog.csdn.net/guxiaoshi/article/details/5009604
 

posted on 2011-08-15 14:57 BobLiu 阅读(...) 评论(...) 编辑 收藏