12

首先,我需要强调的是,这与该线程中的问题略有不同。此外,安装KB2468871也无济于事。

我试图尽可能简化这个问题。一般来说,它是关于使用 Assembly.LoadFile(...) 在桌面应用程序中加载 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()
            );
        }
    }
}

PCL 看起来像这样:

using System.Linq;

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

和 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);
            }
        }
    }
}

当您运行此应用程序时,您会得到绝对正确的结果:

N4: HELLO FROM N4
PCL: HELLO FROM PCL

让我们在 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;
};

因此,如果找不到程序集,它会尝试从“.data”文件加载它。

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

Probing 'C:\xxx\C\bin\Debug\N4.data'
N4: HELLO FROM N4
PCL: HELLO FROM PCL

所以它会通过 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.

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

这就像 Assembly.LoadFile(fileName) is-a no-no 如果加载的程序集是可移植的。

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

您可以在此处找到所有文件。

编辑: 感谢 leppie 强迫我检查其他选项。实际上,我想确保在回答“是的,是的,我试过了”时我没有撒谎。显然这是值得检查的。

来自Suzanne Cook 的 .NET CLR 注释

小心——这些不是一回事。

LoadFrom() 通过 Fusion,如果已经在 LoadFrom 上下文中加载了一个程序集,则可以将其重定向到不同路径但具有相同标识的另一个程序集。LoadFile() 根本不通过 Fusion 绑定 - 加载器只是继续并准确地加载*调用者请求的内容。它不使用 Load 或 LoadFrom 上下文。

4

3 回答 3

5

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

我正在通过 加载存储为资源的所有引用程序集Load(byte[]),这也无法解析2.0.5.0程序集,并且我从System和检索。System.CoreAppDomain.CurrentDomain.GetAssemblies()

于 2013-09-01T18:49:10.830 回答
3

我认为您遇到这些问题是因为:

由于您没有获得最新的 .NET 更新,因此您遇到了异常。

http://www.paraesthesia.com/archive/2013/01/21/using-portable-class-libraries-update-net-framework.aspx

注意 WSUS 部分 - 你可能认为你有最新的更新,但你不会导致你的 WSUS 服务器过时。

此补丁可能会有所帮助,但您最好只获取所有 .net 更新:

http://support.microsoft.com/kb/2468871

(来自上面的评论)

尝试 LoadFrom(...) 而不是 LoadFile(...) / Load(byte[]) 看看是否能解决您的问题?:)

于 2013-10-29T04:29:09.757 回答
1

我遇到了同样的问题,最终得到了以下解决方案:在动态加载 PCL 程序集之前调用以下代码。

Assembly.Load("System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");
Assembly.Load("System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");

如果在加载 PCL 程序集时缺少任何其他依赖项,则只需在上面的代码中添加一行。由于一些奇怪和无法理解的原因,它起作用了。

于 2016-11-12T11:10:00.393 回答