简体   繁体   English

Assembly.LoadFrom在.NET Core和.NET Framework中的工作方式不同

[英]Assembly.LoadFrom works differently in .NET Core and .NET Framework

I have two .csproj projects, with the exact same source code: 我有两个.csproj项目,它们的源代码完全相同:

using Newtonsoft.Json.Linq;
using System;
using System.Reflection;
class Program
{
    static void Main(string[] args)
    {
        Assembly jsonAssembly = Assembly.LoadFrom(@"C:\path\to\Newtonsoft.Json.dll");
        Type reflectionType = jsonAssembly.GetType("Newtonsoft.Json.Linq.JObject");

        Console.Write("Types match: " + (reflectionType == typeof(JObject)));
        Console.Write("Typenames match: " + (reflectionType.FullName == typeof(JObject).FullName));

        JObject cast = (JObject)Activator.CreateInstance(reflectionType);
        Console.Write("Success!");
    }
}

Both .csproj files have an identical reference to Newtonsoft.Json: 这两个.csproj文件对Newtonsoft.Json的引用相同:

<Reference Include="Newtonsoft.Json">
  <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
</Reference>

The only difference between the two projects is that I created the first one using .NET Core 2.0, and the second one using .NET Framework 4.6.1. 这两个项目之间的唯一区别是,我使用.NET Core 2.0创建了第一个项目,而使用.NET Framework 4.6.1创建了第二个项目。

Framework: 框架:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{A6D2C332-B60D-41F1-9983-DE10065973A1}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>ConsoleApp1</RootNamespace>
    <AssemblyName>ConsoleApp1</AssemblyName>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Newtonsoft.Json">
      <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Core: 核心:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Newtonsoft.Json">
      <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

When I run the above code using .NET Core, I get the following response: 当我使用.NET Core运行以上代码时,得到以下响应:

Types match: True
Typenames match: True
Success!

When I run the above code using .NET Framework, I get the following response: 当我使用.NET Framework运行上述代码时,得到以下响应:

Types match: False
Typenames match: True

Unhandled Exception: System.InvalidCastException: [A]Newtonsoft.Json.Linq.JObject cannot be cast to [B]Newtonsoft.Json.Linq.JObject

Why do .NET Framework and .NET Core work differently when loading assemblies via reflection? 为什么通过反射加载程序集时.NET Framework和.NET Core的工作原理不同?

The problem maybe is, that in .NET Framework you use 2 different assemblies (2 different files on disk). 问题可能是,在.NET Framework中,您使用2个不同的程序集(磁盘上2个不同的文件)。 Try to run the .NET Framework project in debug mode and see where these types are coming from or add these lines. 尝试以调试模式运行.NET Framework项目,并查看这些类型来自何处或添加这些行。

Console.Write("Reflection type module: " + (reflectionType.Module.FullyQualifiedName));
Console.Write("Static type module: " + (typeof(JObject).Module.FullyQualifiedName));

Inspired by Walter Branson's answer, I did some research and found how some of the Load methods behave. 受沃尔特·布兰森(Walter Branson)的回答启发,我进行了一些研究,发现某些Load方法的行为。

    /* Loads closest assembly given by FullName loaded by default, in this case it is from the same location as executable */
    Assembly jsonAssembly1 = Assembly.Load(@"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed");

    /* Loads assembly exaclty from the file specified by path */
    Assembly jsonAssembly2 = Assembly.LoadFile($@"{pathToAssembly}\Newtonsoft.Json.dll");

    /* In NET.Framework loads same assembly as LoadFrom, but in .NET Core loads same assembly as Load */
    Assembly jsonAssembly3 = Assembly.LoadFrom($@"{pathToAssembly}\Newtonsoft.Json.dll");

I believe this is occurring because the reference compare fails for .NET. 我相信这是因为.NET的引用比较失败。 When you look at the objects there is a different handle in .NET. 当您查看对象时,.NET中有一个不同的句柄。 When you look at the objects in core they both have same handle. 当您查看核心中的对象时,它们都有相同的句柄。

I think this occurs because you are loading the assembly from file. 我认为这是因为您正在从文件加载程序集。 Try loading the assembly by its fully qualified name. 尝试使用其完全限定的名称加载程序集。

Assembly jsonAssembly = Assebmly.Load("NewtonSoft.Json,Version=12.0.0.0,Culture=neutral,PublicKeyToken=30adfe6b2a6aeed")

.NET Framework one copies the .dll that you are referencing to its executable directory. .NET Framework会将您引用的.dll复制到其可执行目录。 So the loaded .dlls are actually different. 因此,加载的.dll实际上是不同的。

Try to change the path from "C:\\path\\to\\Newtonsoft.Json.dll" in .NET Framework project to "Newtonsoft.Json.dll" , the result will be the same as in .NET Core one. 尝试将.NET Framework项目中的路径从"C:\\path\\to\\Newtonsoft.Json.dll"更改为"Newtonsoft.Json.dll" ,结果将与.NET Core中的结果相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM