简体   繁体   中英

The type “Action<T1,T2,T3>” exists in 2 DLLs, how do I specify which one to use or just avoid one?

I making an app with Unity3D and using this socket.io plugin but when I'm using Unity 2019.1 I get the following errors:

/.../Unity.app/Contents/Resources/PackageManager/BuiltInPackages/com.unity.timeline/Runtime/TrackAsset.cs(17,38): error CS0433: The type 'Action<T1, T2, T3>' exists in both 'WebSocket4Net, Version=0.14.1.0, Culture=neutral, PublicKeyToken=eb4e154b696bf72a' and 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

And that is because Action is defined both in WebSocket4Net, which I use, even tho I'm not using that specific reference and in System, which again, I'm not using.

System.Action is being used by Unity, while the one in WebSocket4Net is used to make JSON from the library Newtonsoft.Json, which I'm not using but is strictly linked to the WebSocket4Net and can't be removed.

I tried specifying System.Action whenever Unity uses that, but that's no solution, the error is still there.

Tried removing WebSocket4Net and this removes that error, but create a new error:

'HashSet<GameObject>' does not contain a definition for 'Contains' and no accessible extension method 'Contains' accepting a first argument of type 'HashSet<GameObject>' could be found (are you missing a using directive or an assembly reference?)

when HashSet should have this method by default.

Tried removing all 3 DLLs from the plugins folder in order to avoid having these issues, but then I won't have sockets,

Is there any way to fix this? I don't want to dive into the libraries to bugfix that, but is there any other solution?

I'm assuming that you mean "in the same full namespace"; if that assumption is incorrect and they're simply in different namespaces , then: just use full name qualification, ie global::Foo.Bar.Whatever instead of just Whatever . You can also add a "using alias" on a per-file basis for convenience, ie

using Mwahaha = global::Foo.Bar.Whatever;

and now you can use Mwahaha as an alias every time you mean global::Foo.Bar.Whatever in that file .


So; going back to my assumption that you mean "in the same full namespace":

Conflicting full type names is a major pain, and how to fix it depends a lot on your build chain. The simplest fix here is to encourage library authors not to do this , perhaps using [assembly:TypeForwardedTo(...)] if the thing they added for compatibility is now available in an "official" location (ie if library A adds a type, then later the "official" version is added somewhere, library A can delete their version of it, and add [assembly:TypeForwardedTo(typeof(TheType))] where TheType is now from the "official" library, and everything should work correctly without even breaking callers, if the types are truly compatible; callers expecting the type in A will be redirected to the official version automatically without even needing to be recompiled).

Otherwise...

The compiler supports this, but via something called "extern aliases". When you reference any dll, by default it gets the global namespace alias. However, specifically for this scenario , you can override that and tell it which namespace to use on a per-dll basis. So you could say that everything from a.dll goes into global (ie the default), but everything from b.dll goes into the blah namespace alias. You then need to use extern alias in every single file where you want to access things from blah (ie from b.dll ). This gets annoying very quickly, but works. The short version would be:

extern alias blah;

and then use blah::Foo.Bar.Whatever in every location in that file to refer to Foo.Bar.Whatever from b.dll ; or combined with "using alias":

extern alias blah;
using Mwahaha = blah::Foo.Bar.Whatever;

and now Mwahaha refers to Foo.Bar.Whatever from b.dll but only in that file .


The article above covers how to specify the per-dll aliases with csc , but in reality almost nobody uses csc directly.

For old-style csproj in Visual Studio, the alias can be specified in the properties window of the reference. For new-style csproj, you have to use an ugly hack:

  <Target Name="ChangeAliasesOfReferences"
    BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
    <ItemGroup>
      <ReferencePath Condition="'%(FileName)' == 'b'"><!-- the dll -->
        <Aliases>blah</Aliases><!-- the namespace aliases -->
      </ReferencePath>
    </ItemGroup>
  </Target>

As for how to do this with the unity build chain: your guess is as good as mine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM