Repository navigation
Multiple UnitsNet versions being loaded into same context #1733
|
Hello 👋 Been a while, but here I am with something I'm running into: Whilst working on an AutoCAD plugin. I started using UnitsNet v5 for the algorithm I was working on. After a brief investigation, I came to the conclusion that one of the issues was the fact that we were shipping v5, whilst the other plugin shipped v4. Now here comes the fun part: Our plugin loads upon startup of AutoCAD - theirs load on demand (as soon as a command defined in their plugin is executed by the user) Whenever the other plugin executes No errors, nothing Any thoughts on how to go about this? Options i'm considering:
|
Replies: 1 comment 3 replies
|
The public enum LengthUnit
{
- Undefined = 0,
/// <summary>
/// Angstrom is a metric unit of length equal to 1e-10 meterThat's the whole thing. Every other member kept its explicit value, What's actually biting you is older than v5. Explicit values only arrived in 4.133.0. Before that every member was an implicit ordinal in alphabetical order, so any new unit anyone contributed shifted everything after it. Here's 4.118.0: public enum LengthUnit
{
Undefined = 0,
AstronomicalUnit,
Centimeter,
Chain,
Decimeter,
DtpPica,
...Count those out and So the lightyears aren't generic corruption, they're a fingerprint. They pin the other plugin to a UnitsNet between 4.50.0 and 4.118.0. Had it been built against 4.119.0 you'd be seeing megalightyears, and against 4.120.0 through 4.129.0, megaparsecs. That's the same mechanism as #1068, where a library on 4.107.0 was consumed by an app on 4.126.0 and produced megalightyears, because 18 is That got fixed in 4.133.0 by #1097, which fixes #1068. Values now live in /// Allocates unique enum values per quantity and persists the mapping to a JSON file to ensure the values do not
/// change when adding new units.angularsen confirmed the same in #1114, "as of v4.133.0, at least the enum values should now be stable". In that JSON at 5.75.1, Two corrections to the framing. First, Second, downgrading yourselves to v4 isn't neutral, it's worse. Any v4 you ship advertises Cheapest test before you build anything, and don't use the file version for it. Get-ChildItem "C:\Path\To\TheirPlugin" -Recurse -Filter UnitsNet.dll |
ForEach-Object { "$($_.FullName) $((Get-Item $_.FullName).VersionInfo.ProductVersion)" }4.118.0 comes back as Now the question I'd actually chase, which is why anything is unifying at all. Both packages are strong-named with the same key. I pulled the DLLs off nuget.org and the public key token is What that buys you depends on which runtime AutoCAD hands you, and this is the part I'd nail down first. On .NET Framework those two identities load side by side in one AppDomain with no config at all, so something in your process is overriding it, either a binding redirect in AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == new AssemblyName(e.Name).Name);Whatever you hand back from On .NET there's nothing to override, because the default Either way, confirm which world you're in from a scratch command once both plugins are loaded: foreach (var a in AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name == "UnitsNet"))
ed.WriteMessage($"\n{a.FullName}\n {a.Location}");Two lines means side by side is working and the bug is somewhere else. One line means you've found it, and the runtime tells you whether it's your resolver or just how that loader works. Of your three options I'd take the alias. It renames and fixes references so nothing can match you by simple name again, which is the one fix that works under both loaders. Pass Two things queued up behind this. All of v5 pins |
The ALC route should work, and the reason it fixes the customer's bug is slightly different from isolation — it's that you stop occupying the default context. Their v4 loads there cleanly once yours isn't sitting in it first. That's worth using as the acceptance test: after the change, load their plugin and confirm
Lengthresolves to 4.x in Default.The same framing gives you the constraint. Nothing in the default context may touch a UnitsNet type — not a parameter, not a return, not a local in a method that never runs. First reference triggers a Default load and you're back where you started. So the isolated assembly's public surface has to be UnitsNet-free: primitives, or types from an …