UPDATE:
The question is much harder to explain than I thought.
- I have 2 projects. (.NET 6.0)
- Each project is a NuGet package.
- The packages MUST NOT DEPEND ON EACH OTHER. (Each one must be able to be used separately.)
- If package
B
detects packageA
referenced (by that I mean using a<ProjectReference>
or<Package Reference>
tag in.csproj
file - it should load the package A and execute a method from it.
By now I have it done like that:
(Package B code)
try {
var assembly = Assembly.Load("A");
var type = assembly.GetTypes.FirstOrDefault(t => t.Name == "MyKnownType");
var instance = (IApiOfA)Activator.CreateInstance(t);
instance.MethodOfA(someDataIHaveInB);
}
catch { }
I hate abusing exceptions. My question is how to do it skipping the exception part.
Querying AppDomain.CurrentDomain
doesn't help - it only gets the LOADED assemblies.
Also Assembly.GetEntryAssembly().GetReferencedAssemblies()
does not work, it doesn't even show my target assembly when I explicitly load it.
AppDomain.CurrentDomain.Evidence
is not available in .NET 6.0.
Any clues?
ANOTHER UPDATE: This: Check if Assembly Exists by name before loading it
As someone else says: exceptions are not always that bad. Maybe they are not the most elegant way, but there's a trade off. That one simple check will save a lot of time in application development. What the package does it something that can be easily be overlooked and lead to a lot of wasted time on figuring out why it doesn't work. And now, when A and B are included in project, the correct interaction will always be done and both won't fail. If there's only one of those packages - there is no problem, the issue doesn't exist. If they are used both, they cooperate. So I was just looking for a micro-optimization :)
CodePudding user response:
You will need a custom build step that embeds the list of all references into the resulting executable. The Microsoft tools do not, they only emit metadata for those dependencies which are actually used and needed (although they don't actually have to be present at runtime, due to lazy loading of dependencies any methods that don't consume the missing dependency can still run correctly).
Adding more <PackageReference>
entries to your project file doesn't result in any change to the compiler output, it just allows you to write code using them, and the presence of that code is what influences the output.
CodePudding user response:
My current solution, tested on both Windows and Linux, with single file builds.
/// <summary>
/// Resolves available API members.
/// </summary>
internal static class ApiResolver {
/// <summary>
/// Gets an instance of the specified type.
/// If it's not already loaded, the target assembly will be loaded.
/// </summary>
/// <typeparam name="TInterface">Type interface.</typeparam>
/// <param name="assemblyName">Assembly name.</param>
/// <param name="typeName">Type name.</param>
/// <returns>Instance or null if not found.</returns>
public static TInterface? GetInstance<TInterface>(string assemblyName, string typeName) where TInterface : class {
Type? type;
try {
var assembly = Assembly.Load(assemblyName);
type = assembly.GetType(typeName);
}
catch { return null; }
return type is null ? null : (TInterface?)Activator.CreateInstance(type);
}
}
It returns null if it can't get the instance. So it can be nicely used like this:
var myTarget = ApiResolver.GetInstance<IMyTargetApi>("OtherModule", "TheClass");
myTarget?.DoSomeStuff(withSomeData);
Of course there is a requirement that the target class must implement a known interface. But this requirement is met by my packages. If it wouldn't be met, it is still solvable by using the Reflection
, but that would be messy.