简体   繁体   中英

Why does this generic cast fail

I have the following code:

kAIDataPort<T> lOtherEndCast = ( kAIDataPort<T>)lOtherEnd;

Which raises the following exception:

[A]kAI.Core.kAIDataPort`1[UnityEngine.GameObject] cannot be cast to 
[B]kAI.Core.kAIDataPort`1[UnityEngine.GameObject]. Type A originates from 'kAICore...

(Exception shrunk for readability, but there is no difference between A and B.

All the other questions on generic casting seem to relate to lists and inherited types, but here we just have an object of a certain type and not being able to cast it to precisely that type.

Not looking for a work around, I am using a non-generic base class with a non-typed method to do what I need to do, I just want to understand why this raises an exception.

This is in .NET 3.5 (since using Unity which still doesn't support .NET 4...)

Full exception:

[A]kAI.Core.kAIDataPort`1[UnityEngine.GameObject] cannot be cast to 
[B]kAI.Core.kAIDataPort`1[UnityEngine.GameObject]. 
Type A originates from 'kAICore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'E:\dev\C#\kAI\kAI-Editor\bin\Debug\kAICore.dll'. 
Type B originates from 'kAICore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'E:\dev\C#\kAI\kAI-Editor\bin\Debug\kAICore.dll'.

Update:

The problem was loading the Unity DLL twice, but it was loading the same DLL (but never unloading). The code for this is:

FileStream lDLLStream = lDllPath.GetFile().OpenRead();
byte[] lDLLArray = new byte[lDLLStream.Length];
lDLLStream.Read(lDLLArray, 0, (int)lDLLStream.Length);
lDLLStream.Close();
Assembly lLoadedAssembly = Assembly.Load(lDLLArray);

// Force the loading of the dll
lLoadedAssembly.GetExportedTypes();

return lLoadedAssembly;

The path was the same both times, so why would the case get confused about which dll to load from?

Further, loading the DLL twice this way and examining the following things just before the exception I get:

this.GetType().Equals(lOtherEnd.GetType())  false

but on the generic argument:

typeof(T).Equals(lOtherEnd.GetType().GenericTypeArguments[0])   true

It's a generic type - the cast checks four types: T1<T2> versus T3<T4> .

So, the collision can be either T1<G> vs T2<G> OR it can be T<G1> vs T<G2> .

The debug messages only printed information about 'T' and indeed it seems the same. So, check the Gs.

EDIT:

Now I would not guess you'd do that. You were precisely generating multiple images of the same assembly. All types created from them would always be different.

\n

An assembly that is loaded FROM BYTES is never 'equal' to any other assembly. It is always loaded with new handle and never "coerced/collapsed" with any already loaded assembly. It is always described as having null codebase/location and treated similarily to "dynamic assemblies", created on-the-fly. ( I tried to find a reference for that and I cannot. I'm still quite sure about it, but I'm striking it just to warn you that it may not be true. Here's a starter for reading about assembly loading contexts: What are 3 kinds of Binding Contexts for? )

Why do you load it from raw bytes? Load it from FILE/PATH. Then it will get its codebase/location set properly and multiple loads will results in only one handle in memory.

It seems you're casting a type T1 from assembly A1 to T1 in assembly A2 . Indeed both are not same. So it fails.

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