"动态加载可移植类库时无法加载文件或程序集'System.Core,Version = 2.0.5.0,..."异常

Mil*_*ski 12 .net c# reflection .net-assembly

首先,我要强调,这是稍微比一个不同的问题,这个线程.此外,安装KB2468871没有帮助.

我试图尽可能地简化这个问题.一般来说,它是关于使用Assembly.LoadFile(...)在Desktop应用程序中加载PCL程序集.

假设有一个.NET 4.0控制台应用程序(称为"C").它引用了.NET 4.0程序集(称为"N4")和PCL程序集(称为"PCL").

N4看起来像这样:

using System.Linq;

namespace N4
{
    public class ClassInN4
    {
        public static string Greet()
        {
            return new string(
                "hello from N4"
                .ToCharArray()
                .Select(char.ToUpper)
                .ToArray()
            );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

PCL看起来像这样:

using System.Linq;

namespace PCL
{
    public class ClassInPCL
    {
        public static string Greet()
        {
            return new string(
                "hello from pcl"
                .ToCharArray()
                .Select(char.ToUpper)
                .ToArray()
            );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和C看起来像这样:

using System;
using System.IO;
using System.Reflection;
using N4;
using PCL;

namespace C
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Test();
            Console.ReadLine();
        }

        private static void Test()
        {
            Test("N4", ClassInN4.Greet);
            Test("PCL", ClassInPCL.Greet);
        }

        private static void Test(
            string title, 
            Func<string> generator)
        {
            try
            {
                Console.WriteLine(
                    "{0}: {1}", title, generator());
            }
            catch (Exception e)
            {
                Console.WriteLine(
                    "{0}: {1} -> {2}", title, e.GetType(), e.Message);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行此应用程序时,您将获得绝对正确的结果:

N4: HELLO FROM N4
PCL: HELLO FROM PCL
Run Code Online (Sandbox Code Playgroud)

让我们在Program.Main中将AssemblyResolve事件添加到CurrentDomain:

AppDomain.CurrentDomain.AssemblyResolve += (_, a) => {
    var fileName = Path.GetFullPath(
        new AssemblyName(a.Name).Name + ".data");
    Console.WriteLine("Probing '{0}'", fileName);
    return 
        File.Exists(fileName) 
        ? Assembly.LoadFile(fileName) 
        : null;
};
Run Code Online (Sandbox Code Playgroud)

那么,如果无法找到程序集,它会尝试从".data"文件加载它.

让我们去应用程序文件夹并将"N4.dll"重命名为"N4.data"并运行"C.exe".

Probing 'C:\xxx\C\bin\Debug\N4.data'
N4: HELLO FROM N4
PCL: HELLO FROM PCL
Run Code Online (Sandbox Code Playgroud)

所以它通过AssemblyResolve并最终加载"N4.data"并且工作与原始一样好.

让我们将"N4.data"还原为"N4.dll"并将"PCL.dll"重命名为"PCL.data"并...

Probing 'C:\xxx\C\bin\Debug\PCL.data'
N4: HELLO FROM N4
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
PCL: System.IO.FileNotFoundException -> Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.
Run Code Online (Sandbox Code Playgroud)

请注意,PCL程序集加载得很好,问题是,它只能找不到它的依赖项(System.Core)了.

就像Assembly.LoadFile(fileName)是一个禁止 - 如果加载的程序集是可移植的.

有人有这个问题吗?有人解决了这个问题吗?

你可以在这里找到所有文件.

编辑: 感谢leppie强迫我检查其他选项.当我回答"是的,是的,我试过"时,我其实想确定我不会撒谎.显然值得一试.

来自Suzanne Cook的.NET CLR备注:

小心 - 这些不是一回事.

LoadFrom()通过Fusion,可以重定向到另一个路径,但是如果已经在LoadFrom上下文中加载了相同的身份,则可以使用相同的身份.LoadFile()根本没有通过Fusion绑定 - 加载器只是继续并正好加载*调用者请求的内容.它不使用Load或LoadFrom上下文.

小智 5

当被要求提供版本时,您可以从事件中返回System.Core平台的组件(例如version 4.0.0.0 for .NET Framework 4.0).AssemblyResolve2.0.5.0

我正在加载存储为资源的所有引用的程序集Load(byte[]),这也无法解析2.0.5.0程序集,我检索两者SystemSystem.CoreAppDomain.CurrentDomain.GetAssemblies().