ltrzesniewski / InlineIL.Fody

Inject arbitrary IL code at compile time.
MIT License
240 stars 17 forks source link

Add a way to get a TypeRef from an assembly at provided path #31

Closed MichalPetryka closed 5 months ago

MichalPetryka commented 7 months ago

It would be useful to be able to able to get a TypeRef to an assembly that's not referenced by the project, maybe by adding a new TypeRef constructor that takes a path to a dll and a type name there and adds it as a reference to the output assembly.

ltrzesniewski commented 7 months ago

Having a path to a dll in the source code doesn't feel clean to me.

May I ask why do you want this feature, and what prevents you from referencing the assembly?

MichalPetryka commented 7 months ago

May I ask why do you want this feature, and what prevents you from referencing the assembly?

Me and other contributors to dotnet/runtime sometimes use your InlineIL for testing how the runtime behaves with certain IL patterns, adding this would also make it easier to test new and internal APIs added to the runtime which can't be accessed through normal code due to IDEs building it against older reference assemblies that are stripped of internal APIs. With this you could emit calls to such APIs by making the output reference the locally built runtime while still using a proper IDE.

ltrzesniewski commented 7 months ago

I see. That's a valid use case. :+1:

However, accessing new runtime APIs may be more difficult than it seems:

...or I could just add a reference to the custom dll and not care about these issues, I'm just not sure you'd end up in a valid state (you could have two references to the same assembly name for example).

I also wonder about the syntax: TypeRef.FromDll("<path>", "<type>") or [assembly: InlineIL.AddAssemblyReference("<path>")] or maybe an <InlineIL.AssemblyReference Include="<path>" /> item in the csproj?

Speaking of the csproj, wouldn't tweaking the output of the ResolveAssemblyReference task be sufficient for this? Maybe even modifying @(Reference) items could do the job? I feel that handling this through MSBuild would be a better fit than doing it with InlineIL.

What do you think?

(also, Fody's AssemblyResolver would be unaware about the custom dll, and that may cause issues or require changes, but that's an implementation detail)

MichalPetryka commented 7 months ago

I think that adding a 2nd reference would be fine here, the normal ones would then refer to System.Runtime and be forwarded at runtime while the emitted ones would call System.Private.CoreLib directly. As for syntax, I think that TypeRef.FromDll("<path>", "<type>") would be the best since it would clearly show which dll version the type is coming from. IIRC MsBuild handles reference assemblies to framework differently from the rest and gets quite unhappy when trying to replace them, I don't recall the details though.

ltrzesniewski commented 6 months ago

Ok, I released v1.9.0-pre1 with this feature. Please test it and tell me if it behaves as you expect.

I'm not sure yet if I want to merge this change TBH, as this required a lot of changes in the existing code, much more than I expected, because of the way Fody and Cecil are structured.

In any case, the FromDll method will remain marked as experimental, as I fully expect it to cause issues (such as other weavers down the chain not being able to resolve the injected symbols for instance).

MichalPetryka commented 5 months ago

Please test it and tell me if it behaves as you expect.

It seems to be working nicely, one small improvement would be if it could recognize typeof(X).FullName in addition to just string literals for the type name. Can't say I have any opinion on the code changes required as I don't know the code here. I agree with keeping it as experimental too as this option is only useful for experimenting around I'd say.

ltrzesniewski commented 5 months ago

Cool! 🙂

Maybe I could add an overload with System.Type instead of (or in addition to) handling typeof(X).FullName. Since X would need to be an element type (in the sense of not being a type spec like X[] or X*), it wouldn't make sense to have an overload with InlineIL.TypeRef here.

I think I'll rename the method to something like FromDllFile, maybe simplify the code a bit, add a few more tests then merge this. I'll probably release a v1.9.0-pre2 with those changes, but I won't release a stable version until I have a non-experimental feature to ship. 🙂

ltrzesniewski commented 5 months ago

I pushed v1.9.0-pre2 with these changes.