dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.25k stars 4.73k forks source link

PersistedAssemblyBuilder, types throw exceptions even after created #108733

Open snakex64 opened 3 weeks ago

snakex64 commented 3 weeks ago

Description

Hi! I have been trying the new PersistedAssemblyBuilder in .net 9. I have been using the previous AssemblyBuilder.DefineDynamicAssembly to create assemblies at runtime but it seems like the new one might be missing some features.

I use ExpressionTree to create the method's body, and then compile those expression tree directly in the ILGenerator of that method. I had issues in the past where I couldn't get information about properties and methods out of the type until I call TypeBuilder.CreateType() on it, then everything works fine, such as type.GetProperties() or type.GetProperty(name)

It seems now that even if I call CreateType() on the type builder, I still can't call most of the usual reflection methods such as GetProperties() Is there a way around this?

To make it work in the past, I ended up creating internal static classes that contain the actual implementation. That allowed me to have one class that had "empty methods", basically generating the IL code to do something like:

public int MyMethod(int a, int b)
{
    return MyInternalStaticClass.MyMethod(this, a, b);
}

That way I could call CreateType() on that type before I actually know what to put inside the method itself, since I sadly can't do that before the type is created. It seems now that my fix might not be enough anymore.

Reproduction Steps

In .NET 9 RC1 Use the PersistedAssemblyBuilder to create a class, create the type and call GetProperties() on created "Type"

Expected behavior

I would expect the "Type" object to behave normally and provide all necessary information normally

Actual behavior

A lot of methods are clearly just throwing exceptions and don't have implementations at all. Such as "GetInterfaces()" has an implementation but "GetInterface" doesn't, even though they both ping back on the same backend object.

Image

Regression?

It used to work with the previous AssemblyBuilder.DefineDynamicAssembly but since we can't use it anymore to save dynamic assemblies I don't have a choice but to use the new PersistedAssemblyBuilder

Known Workarounds

No response

Configuration

.NET 9 RC1

Other information

No response

dotnet-policy-service[bot] commented 3 weeks ago

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

buyaa-n commented 3 weeks ago

A lot of methods are clearly just throwing exceptions and don't have implementations at all. Such as "GetInterfaces()" has an implementation but "GetInterface" doesn't, even though they both ping back on the same backend object.

Yes, we tried to implement as much as we can, but there are still lot of methods that are not implemented, some of them even could not be implemented. But the methods you are requesting are can be implemented.

@snakex64 If you like you could also contribute and implement those methods. This should be quite similar to the GetFields(BindingFlags) API you showed in the picture plus adding unit tests

snakex64 commented 3 weeks ago

@snakex64 If you like you could also contribute and implement those methods. This should be quite similar to the GetFields(BindingFlags) API you showed in the picture plus adding unit tests

I sure can try. Can you point me towards where to add the tests ? I had a quick look yesterday but I'm not sure.

Adding the code is the easy part, I'll try to get a setup working

buyaa-n commented 3 weeks ago

Great, thank you!

type.GetProperties() or type.GetProperty(name) tests can be added to AssemblySavePropertyBuilderTests

If you add GetInterface(...) implementation test could be added to AssemblySaveTypeBuilderAPIsTests

Here is instructions how to build and run tests Running tests for a single library

snakex64 commented 4 days ago

@buyaa-n I added a PR. Really not sure about the GetProperty as it was a bit more complicated to do, hopefully it's at least a good starting point.