-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Discussion: Provide an easier way to add MetaDataReferences from Types #65627
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
You should be able to use |
Thanks for that - that looks promising but... I had no luck getting this to work. Basically what I'm now doing is this: /// <summary>
/// Adds an assembly reference from an existing type
/// </summary>
/// <param name="type">any .NET type that can be referenced in the current application</param>
public bool AddAssembly(Type type)
{
try
{
// *** TODO: need a better way to identify for in memory dlls that don't have location
if (References.Any(r => r.FilePath == type.Assembly.Location))
return true;
if (string.IsNullOrEmpty(type.Assembly.Location))
{
#if NETCORE
unsafe
{
bool result = type.Assembly.TryGetRawMetadata(out byte* metaData, out int size);
var bytes = new byte[size];
for (int i = 0; i < size; i++)
{
bytes[i] = metaData[i + 1];
}
var ref1 = MetadataReference.CreateFromImage(bytes);
References.Add(ref1);
}
#else
return false;
#endif
}
else
{
var systemReference = MetadataReference.CreateFromFile(type.Assembly.Location);
References.Add(systemReference);
}
}
catch
{
return false;
}
return true;
}
When this code triggers with an in-memory assembly the
I suppose it's possible I need to add this when I compile the assembly but not sure what triggers that. |
I see, we don't have a readily available factory that takes only the metadata blob -- CreateFromImage takes PE image (the entire dll/exe file), but TryGetRawMetadata only returns the metadata section of that file. You'll need to construct AssemblyMetadata object and then call GetReference on it. First, use ModulMetadata.CreateFromMetadata to create ModuleMetadata and pass it to AssemblyMetadata.Create. |
Thank you... this gets me a little closer now: if (string.IsNullOrEmpty(type.Assembly.Location))
{
#if NETCORE
unsafe
{
bool result = type.Assembly.TryGetRawMetadata(out byte* metaData, out int size);
var moduleMetaData = ModuleMetadata.CreateFromMetadata( (nint) metaData, size);
var assemblyMetaData = AssemblyMetadata.Create(moduleMetaData);
References.Add(assemblyMetaData.GetReference());
}
#else
return false;
#endif
}
else
{
var systemReference = MetadataReference.CreateFromFile(type.Assembly.Location);
References.Add(systemReference);
} Roslyn can now resolve the reference and compile the code which I guess solves this particular problem... It would be nice if there was a more obvious way to do this - like an overload that can use an active type to create the metadata reference (presumably using similar code). Thank you... The next problem though is that the runtime activation can't find the assembly when instantiating the top level type with
A bit odd because the type is already loaded since it was used to access the meta data reference and in the sample code even has an active instance. But... that's a separate issue somewhat unrelated to Roslyn and MetaDataReferences. |
Background and Motivation
I hope this is in the right place for a discussion.
I have a small scripting library that is built ontop of Roslyn compiler libraries to dynamically compile C# code into assemblies/types.
One huge sticking point in usage of this tooling is the complexity of adding
MetaDataReferences
. There are a number of issues but there's at least one scenario that I have no solution for:This came up from a user who was trying to use multiplate compilations and then use the output from prior compilations in another new compilation.
What doesn't work:
What does work (hack):
The issue here is that currently I use the assembly location to load the MetaDataReference:
This works with on-disk assemblies, but doesn't with in-memory assemblies (which actually live on disk?) which don't return a type.Assembly.Location. I could not figure out a way to create a
MetaDataReference
from the in-memory type (or assembly).Specific question: Is there a way to get a MetaDataReference off an in-memory compiled type?
To give some context - this is roughly the code the user provided as a scenario. He basically is using multiple compilations of types with type 1 compiled and instantiated and then trying to pass this type 1 to a compilation of type 2.
The code fails because it can't resolve the
MetaDataRefernce
from the first type (in-memory compiled) astype.Assembly.Location
which for the in-memory dll is blank. If I uncomment the line to explicitly write out an assembly to disk (script.OutputAssembly = "..."
) the code below works.code link in Westwind.Scripting repo
Proposal
Overall creating and providing of MetaDataReferences is a pain in the butt currently. If you want to avoid loading the reference libraries runtime references of the .NET core libraries there's almost no rhyme or reason to what's included and what's not. The problem with the reference. Also these are not officially provided by Microsoft which seems odd (Jared Parsons maintains those).
It would be really helpful at minimum if
MetaDataReference
had some additional methods for loading a reference directly from a type so it can work of dynamically created types.The text was updated successfully, but these errors were encountered: