Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Reflection.Emit value type mismatch trying to create a value type #103796

Closed
Zorbn opened this issue Jun 21, 2024 · 5 comments · Fixed by #104055
Closed

System.Reflection.Emit value type mismatch trying to create a value type #103796

Zorbn opened this issue Jun 21, 2024 · 5 comments · Fixed by #104055

Comments

@Zorbn
Copy link

Zorbn commented Jun 21, 2024

Description

I'm trying to create a value type using the .NET 9 System.Reflection.Emit API. I wasn't able to find an example, so I tried to just define a type with a parent type of System.ValueType. Unfortunately, I get the following error when I run an assembly that uses the type. My guess is that there is a different, intended way to define a value type.

Unhandled Exception: System.TypeLoadException: Could not load type 'myValueType' from assembly 'MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' due to value type mismatch.

Reproduction Steps

Define and create a type extending System.ValueType, then use it by declaring a local.

var context = new MetadataLoadContext(resolver);
var valueType = content.CoreAssembly!.GetType("System.ValueType")!;
var myValueType = moduleBuilder.DefineType("myValueType", 0, valueType);
// ...
myValueType.CreateType();
// ...
ilGenerator.DeclareLocal(myValueType);

Expected behavior

Either extending from System.ValueType works, or there is some other way to define a value type using System.Reflection.Emit.

Actual behavior

Unhandled Exception: System.TypeLoadException: Could not load type 'myValueType' from assembly 'MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' due to value type mismatch.

Regression?

No response

Known Workarounds

No response

Configuration

Using .NET 9.0.100-preview.5.24307.3 and also using the reference assemblies from that version of .NET for my MetaDataLoadContext resolver.

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jun 21, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection-emit
See info in area-owners.md if you want to be subscribed.

@jkotas
Copy link
Member

jkotas commented Jun 21, 2024

The problem is likely caused by wrong IsValueType value here:

.

cc @buyaa-n

@jkotas jkotas added the bug label Jun 21, 2024
@buyaa-n buyaa-n added this to the 9.0.0 milestone Jun 21, 2024
@buyaa-n buyaa-n removed the untriaged New issue has not been triaged by the area owner label Jun 21, 2024
@Zorbn
Copy link
Author

Zorbn commented Jun 22, 2024

Here's a full example. It only happens when using the MetadataLoadContext's CoreAssembly. When I remove that part it works fine.

using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Loader;

var resolver =
    new PathAssemblyResolver(Directory.GetFiles("C:\\Program Files\\dotnet\\sdk\\9.0.100-preview.5.24307.3\\ref",
        "*.dll"));
using var context = new MetadataLoadContext(resolver);
var coreAssembly = context.CoreAssembly!;

var valueTypeType = coreAssembly.GetType("System.ValueType")!;

var ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), coreAssembly);
var mob = ab.DefineDynamicModule("MyModule");

var valueTb = mob.DefineType("MyValueType", 0, valueTypeType);
valueTb.CreateType();

var tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
var meb = tb.DefineMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Static);
var il = meb.GetILGenerator();
il.BeginScope();
il.DeclareLocal(valueTb);
il.EndScope();
il.Emit(OpCodes.Ret);

tb.CreateType();

using var stream = new MemoryStream();
ab.Save(stream);
stream.Seek(0, SeekOrigin.Begin);
var assembly = AssemblyLoadContext.Default.LoadFromStream(stream);
var method = assembly.GetType("MyType")!.GetMethod("MyMethod");
method!.Invoke(null, null);

@Zorbn
Copy link
Author

Zorbn commented Jun 22, 2024

My local hack/fix for this was to add protected override bool IsValueTypeImpl() => _typeParent?.FullName == "System.ValueType" || _typeParent?.IsValueType == true; to TypeBuilderImpl. Probably not ideal but it's enough to allow me to move forward for now.

@github-actions github-actions bot locked and limited conversation to collaborators Jul 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants