Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by vexe · Mar 16, 2015 at 01:04 PM · c#dllassemblydynamic loading

Circular references between Dlls. firstpass and a generated Dll

EDIT: I ended up using Delegate.Create delegate and hook up my dll dynamically and not statically.

 public void ConnectAssembly(string assemblyPath, string serializerTypeName)
 {
     if (!File.Exists(assemblyPath))
         throw new IOException("Assembly path doesn't exist: " + assemblyPath);

     var asm = Assembly.LoadFrom(assemblyPath);
     var serializerType = asm.GetType(serializerTypeName);

     if (serializerType == null)
         throw new NullReferenceException("Serializer type was not found: " + serializerTypeName);

     var serializeMethod = serializerType.GetMethod("Serialize", BindingFlags.Static | BindingFlags.Public);
     var deserializeMethod = serializerType.GetMethod("Deserialize", BindingFlags.Static | BindingFlags.Public);
     _serialize = (SerializationDelegate)Delegate.CreateDelegate(typeof(SerializationDelegate), null, serializeMethod);
     _deserialize = (DeserializationDelegate)Delegate.CreateDelegate(typeof(DeserializationDelegate), null, deserializeMethod);
 }

EDIT: Here's a video showing it in action:

https://www.youtube.com/watch?v=e-3a6qnVjmM&feature=youtu.be

In my firstpass dll, I have type X - I have a dynamically generated dll 'SerTest.dll' that I emit at in the firstpass, that references 'X'. So when Unity tries to compile firstpass, it tries to compile the dll 'SerTest' which references 'X' in firstpass, compilation fails.

 -----Compiler Commandline Arguments:
 
 Filename: "C:\Program Files\Unity\Editor\Data\Mono\bin\mono.exe"
 
 Arguments: "C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity\smcs.exe"  @Temp/UnityTempFile-71d970fa2565f064492790f199c48fd7
 
 MONO_PATH: C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity
 
 MONO_CFG_DIR: C:\Program Files\Unity\Editor\Data\Mono\etc
 
 index: 68
 
 Responsefile: Temp/UnityTempFile-71d970fa2565f064492790f199c48fd7 Contents: 
 
 -debug
 -target:library    
 -nowarn:0169    
 -out:Temp/Assembly-CSharp-firstpass.dll    
 -r:"C:/Program Files/Unity/Editor/Data/Managed/UnityEngine.dll"    
 -r:"C:/Program Files/Unity/Editor/Data/UnityExtensions/Unity/GUISystem/UnityEngine.UI.dll"    
 -r:Assets/SerTest.dll    <<<<<<<<<< !!!!!
 -r:Assets/Dll/FastSerializer.dll    
 -r:"C:/Program Files/Unity/Editor/Data/UnityExtensions/Unity/GUISystem/UnityEngine.UI.dll"    
 -r:"C:/Program Files/Unity/Editor/Data/Managed/UnityEditor.dll"    
 -r:"C:\Program Files\Unity\Editor\Data\PlaybackEngines\iossupport\UnityEditor.iOS.Extensions.Xcode.dll"    
 -define:UNITY_5_0_0    
 -define:UNITY_5_0    
 -define:UNITY_5    
 -define:ENABLE_LICENSE_RENAME    
 -define:ENABLE_NEW_BUGREPORTER    
 -define:ENABLE_2D_PHYSICS    
 -define:ENABLE_4_6_FEATURES    
 -define:ENABLE_AUDIO    
 -define:ENABLE_CACHING   
 -define:ENABLE_CLOTH    
 -define:ENABLE_DUCK_TYPING    
 -define:ENABLE_FRAME_DEBUGGER    
 -define:ENABLE_GENERICS    
 -define:ENABLE_HOME_SCREEN    
 -define:ENABLE_IMAGEEFFECTS    
 -define:ENABLE_LIGHT_PROBES_LEGACY    
 -define:ENABLE_MICROPHONE    
 -define:ENABLE_MULTIPLE_DISPLAYS    
 -define:ENABLE_NEW_HIERARCHY    
 -define:ENABLE_PHYSICS    
 -define:ENABLE_PHYSICS_PHYSX3    
 -define:ENABLE_PLUGIN_INSPECTOR    
 -define:ENABLE_SHADOWS    
 -define:ENABLE_SINGLE_INSTANCE_BUILD_SETTING    
 -define:ENABLE_SPRITES    
 -define:ENABLE_TERRAIN    
 -define:ENABLE_UNITYEVENTS    
 -define:ENABLE_WEBCAM    
 -define:ENABLE_WWW    
 -define:ENABLE_AUDIOMIXER_SUSPEND    
 -define:ENABLE_NONPRO    
 -define:INCLUDE_DYNAMIC_GI    
 -define:INCLUDE_GI    
 -define:INCLUDE_IL2CPP    
 -define:PLATFORM_SUPPORTS_MONO    
 -define:RENDER_SOFTWARE_CURSOR    
 -define:UNITY_STANDALONE_WIN    
 -define:UNITY_STANDALONE    
 -define:ENABLE_SUBSTANCE    
 -define:ENABLE_TEXTUREID_MAP    
 -define:ENABLE_RUNTIME_GI    
 -define:ENABLE_MOVIES    
 -define:ENABLE_NETWORK    
 -define:ENABLE_MONO    
 -define:ENABLE_PROFILER    
 -define:UNITY_EDITOR    
 -define:UNITY_EDITOR_64    
 -define:UNITY_EDITOR_WIN    

 Assets/Plugins/DemoBehaviour.cs
 
 -r:"C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity\System.Runtime.Serialization.dll"
 
 -r:"C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity\System.Xml.Linq.dll"
 
 -----CompilerOutput:-stdout--exitcode: 1--compilationhadfailure: True--outfile: Temp/Assembly-CSharp-firstpass.dll
 
 Internal compiler error at Assets/Plugins/DemoBehaviour.cs(111,10):: exception caught while emitting MethodBuilder [DemoBehaviour::Demo]
 
 The following assembly referenced from C:\Users\vexe\Desktop\FastSerializer\Assets\SerTest.dll could not be loaded:
 
      Assembly:   Assembly-CSharp-firstpass    (assemblyref_index=1)
 
      Version:    0.0.0.0
 
      Public Key: (none)
 
 The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (C:\Users\vexe\Desktop\FastSerializer\Assets\).
 
 
 
 Could not load file or assembly 'Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
 
 -----CompilerOutput:-stderr----------
 
 
 
 Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
 
     
 File name: 'Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'


To put it in a simplified way, here's what I have:

 public class DemoBehaviour : MonoBehaviour
 {
     void Demo()
     {
         // access code in SerTest.dll
     }

     public class TestClass
     {
         // some fields....
     }
 }

That goes into the firstpass.

Then I emit a dll that references TestClass and does stuff with 'some fields'. The dll is called 'SerTest.dll' and is also located in the firstpass.

I really need to put that dll in the firstpass because I generate serialization code for user types, which could be in any pass, firstpass, plugins etc.

NOTE: I only get the errors when I try to do something with my generated Dll. So say there's a type called "SERIALIZER" in it, in the 'Demo' method, if I do SERIALIZER.Serialize (access the dll statically) I get those errors. I looked around and found this answer - apparently, if I reference the dll dynamically via reflection, it works! so instead of SERIALIZER.Serialize, I do typeof(SERIALIZER).GetMethod("Serialize").Invoke(....) which is really weird...

I really appreciate any help.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Mar 16, 2015 at 01:51 PM

I'm not sure if i fully understood your setup ^^. What seems a bit strange is that your SerText.dll accesses a class / method in a script file (which of course has to be compiled first).

The solution is: Don't reference TestClass from your SerTest.dll.
Now it depends on when and where you need / want to access that TestClass from the SerTest dll. The usual way, the way most native plugins solve "callbacks", is to provide an "Init" method in your SerTest dll that takes an parameter of an interface which your script can implement. So at runtime the first thing you do is to pass an implementation of that interface to your DLL and it's going to store that in a static var. This initialization could even be done from a constructor / static constructor. Of course don't use classes derived from a Unity type for the interface implementation as this will force you to wait for Awake.

If you just need a few simple callbacks, you can also use static delegates in your DLL which will be set from your script classes.

Another way is, like you already mentioned in your question, use reflection from the DLL to access the TestClass (not the other way round).

So it's perfectly fine to statically link / access your "SERIALIZER" from the TestClass as the SerTest dll is already compiled. It makes no sense to introduce a static dependency in your SerTest dll to "Assembly-CSharp-firstpass" as the latter actually isn't compiled yet.

edit

Ok, i just saw your video ^^. This is a very special case. Can't you just "generate" your serializer code as text into script files? :) That way it would be compiled along with the first pass.

If you can't "generate" your code as text, i would suggest that you use reflection to create a delegate to your serialize method at runtime. Or, as said above, use an interface which your serializer implements. That way you just need to call a static method in your SerTest dll via reflection to create an instance and pass back the interface reference.

Comment
Add comment · Show 8 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image vexe · Mar 16, 2015 at 01:54 PM 0
Share

Thanks for your reply! :) - have you seen the video I linked? It explains the setup and why I need to reference user scripts from the generated dll. It's basically a serializer, it 'needs' to know about the user types so it can generate the serialization code for them. I would really like to avoid reflection at all costs, the point of this is to build a very fast serializer that writes directly to a Stream, no temp buffers, no reflection etc.

avatar image vexe · Mar 16, 2015 at 01:57 PM 0
Share

I don't understand why it works when I invoke it via reflection, and not statically... worse case I could use Delegate.CreateDelegate I guess...

avatar image Bunny83 · Mar 16, 2015 at 02:21 PM 0
Share

The problem is, when you compile a dll, all referenced DLLs and used Types must be available at the time of compilation. Since your SerTest.dll references the firstpass DLL, the firstpass DLL has to be available when compiling it. Circular assembly references aren't possible in C#. The only two solutions are:

  • merge them into one assembly (so create your serializaion code as text / script files so they compile along with the rest)

  • use dynamic dispatch via reflection.

avatar image vexe · Mar 16, 2015 at 02:26 PM 0
Share

Read your edit. To give more context. So initially I didn't want to emit to a dll. I use Dynamic$$anonymous$$ethod and emit IL directly. Using the Dynamic$$anonymous$$ethods approach, and creating delegates to those have no problems whatsoever (this is what the #DYNA$$anonymous$$IC define is for at the top of my Demo script) - But I'm also planning to support AOT platforms which don't allow emitting IL. This is why I thought of emitting to an assembly ins$$anonymous$$d of Dynamic$$anonymous$$ethod. Which worked and I got the code I had in $$anonymous$$d. But then I ran into this issue. I'm not sure if I could emit to a file, if that's a thing. One thing I tried to do was to emit to a dll, decompile it and then copy/paste the code to a script lol which 'kinda' worked, except VS hung up due to the large amount of code generated (10k or so), I can't imagine myself asking my users to do that... I will look up emitting to a file, if not I'll just use Delegate.CreateDelegate on the Serialize method in SerTest.dll

avatar image vexe · Mar 16, 2015 at 02:29 PM 0
Share

Responding to your comment, I see. But when we're using reflection, we're doing typeof(SERIALIZER).Get$$anonymous$$ethod(...) aren't we also referring to the dll? I mean I'm still using a type from that assembly, why didn't it complain?

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I get rid of "Assembly-CSharp-firstpass" and "Assembly-CSharp-firstpass.dll" from my Assets? 1 Answer

C# assembly and dll files are not being loaded. 2 Answers

Windows Phone 8.1 Assembly 0 Answers

When I build my game it gives me this error 'Assets/Builds/Build_0.01_Data/Managed/Assembly-CSharp.dll' shouldn't be queried by IsAssemblyCompatible, missing IsInternalOrCompiledAssembly check ? 2 Answers

Unable to debug dynamically loaded assembly DLL that was loaded via Assembly.load() in Unity 5.5.1f1(64 bit) 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges