Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to use partial classes in Unity

Discussion in 'Scripting' started by nsmith1024, Jan 2, 2019.

  1. nsmith1024

    nsmith1024

    Joined:
    Mar 18, 2014
    Posts:
    869
    Hello,

    I have a class that is constantly getting bigger and bigger, so i want to split it into several files, so then it seems i have to use partial C# classes.

    So i have one main class file (partial class) with the same class name, then another file that contains another part of the partial class of the first file, but the second file has a different name from the actual class.

    When i try to drag the second file of the partial class (that file name doesnt not match the class name inside the file) to the gameobject, unity gives an error that it the script class cannot be found.

    Anybody knows the proper way to do partial class in Unity?

    Thanks
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    First and foremost, I'd suggest NOT using partial classes with Unity.

    ...

    If you have your heart set on it.

    Well, you need at least the main portion of the class to have a filename that matches the class name. And when dragging components onto the inspector, ONLY drag that file. The alt-named partial's should not be dragged at all.

    Personally I'd go with a naming convention of something like:
    MyScript.cs
    MyScript.partialX.cs
    MyScript.partialY.cs

    Or something along those lines. This way you know what parts are the partial and which is the main portion. So you don't go dragging the wrong bits around.

    ...

    With that said, I don't know if Unity won't still dislike this.

    In theory the compiler will compile all of the partials together into a single class, and unity will look up that class from the meta data associated with the MyScript.cs.

    (I'm not at home with my Unity dev machine to run any tests of that).

    ...

    AGAIN THOUGH

    I strongly advise not doing this.

    Why is your class getting so large?

    How large is large?

    Couldn't the logic be broken into several scripts, rather than partials? If it's for instance a 'Player' script, and it's doing "attack" "movement" and "inventory management", couldn't all 3 those things be their own scripts?
     
    Ryiah, Bunny83 and Lurking-Ninja like this.
  3. nsmith1024

    nsmith1024

    Joined:
    Mar 18, 2014
    Posts:
    869
    Thanks i got it to work by only dragging in the root partial class to the game object
     
    TheGameLearner likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Actually @lordofduct , I beg to differ with you. Partial classes are great in Unity! You do need to have at least one of the source files named as per what the Editor is expecting, and that one has to inherit from MonoBehavior (the other partials do not). Beyond that Unity is happy.

    I do like and use your file-naming convention, but I tend to use underscores rather than dots.

    Now that all the OO people have fainted and are grasping for smelling salts while they swoon back to consciousness, let me identify some of the many benefits to partials, and how they have helped me.

    For instance, on a larger team (or with older code you have forgotten how it works), breaking functionality out of a MonoBehavior to decant it into other MBs can be perilous, because you can't trivially be sure they're not being used somewhere else, referred to in a Prefab or a Scene.

    (Technically you can find where everything is used with a good search plugin, or just a grep approach looking for GUIDs, but oft times developers skip on this step and thunder ahead, breaking all kinds of assets.)

    It is particularly difficult when you have two release branches going simultaneously as well as a develop branch (large team with continuous deployment). If you start renaming classes and making new GUIDs, you are GOING to have a very very very very bad time in Unity, and you might not realize it until long after all the merge dust settles. Therefore, partials let you keep moving forward confdently.

    For instance, if you find your GameController class growing out of control, breaking it into partial classes can provide both a short-term and a long-term benefit to confidently getting a handle on source size, and also give you a stepping stone to proper refactoring.

    My typical refactor for a complicated class (lets say a massive controller that has too many areas of concern, like areas A, B and C) is to first break it apart into physical files taking advantage of partial classes. It may take several iterative modifications (with full commits to source control in a test branch at each step!) to make sure everything related to each area of concern is in its own file:

    GameController.cs
    GameControllerA.cs
    GameControllerB.cs
    GameControllerC.cs

    At this stage GameController.cs would be pretty much empty, except for Unity methods and inspector-editable fields.

    Now of course at each stage of the way:

    Code (csharp):
    1. git add .; git commit -m "WIP: refactor GameController.cs with partials..."
    With it all pulled apart, you can live with it for a while: For instance, we have third-party vendor classes that encapsulate multiple types of functionality, and there is no advantage to separate classes; ie., our DeltaDNA class handles Eventing, remote control variables, as well as In-App messaging, which is all very tightly bound to the business event cycle with DeltaDNA.

    Or you can start refactoring each area independently: now that you have physically moved areas of concern into individual files, you have a lot better idea of what is involved in breaking it into separate classes, and if that is even a thing you need to do.

    As a point of habit I tend to put all Unity methods in the main class-named file and have explicit calls over to other functions in the other areas of concern, if necessary. Start(), Update(), OnEnable(), etc. all live in GameController.cs . All of this leads to easy debugging and smaller chunks of manageable code in your editor, as well as keeping related code together nicely.
     
    Westland, masterton, m0guz and 3 others like this.
  5. ben-rasooli

    ben-rasooli

    Joined:
    May 1, 2014
    Posts:
    40
    My take on for partial class and partial method is that we can put our business logic(gameplay logic) in one file, and then on a separate file we can put the necessary metadata. By metadata, I mean C# attribute.

    Code (CSharp):
    1. // Player.cs file
    2. public partial class Player : MonoBehaviour
    3. {
    4.     partial void DoSomething()
    5.     {
    6.         //...
    7.     }
    8. }
    9.  
    10. // Player_Metadata.cs file
    11. public partial class Player : MonoBehaviour
    12. {
    13.     [InjectDebugging]
    14.     [InjectProfiling]
    15.     [Conditional("someCondition")]
    16.     partial void DoSomething();
    17. }
    When you work on a larger project, you end up adding lots of C# attributes for lots of methods. I think it's a better way to pull these attributes out into a separate file, otherwise, they clutter your main script file.

    So it's not a solution for breaking up a big class into multiple files. If a class is too big, it's probably not designed well and needs to be broken up into smaller classes, not files.
     
  6. bhermer

    bhermer

    Joined:
    Jun 24, 2013
    Posts:
    28
    **(Technically you can find where everything is used with a good search plugin, or just a grep approach looking for GUIDs, but oft times developers skip on this step and thunder ahead, breaking all kinds of assets.)"[
    **

    Would you be so kind to let me know which search tools you use?
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    For any given asset, look in the .meta file (open it with a text editor) and get the GUID field out. Here is a sample .meta file from one of my prefabs, TrussTower10Assembly_prefab.prefab.meta:

    Code (csharp):
    1. fileFormatVersion: 2
    2. guid: f62bad9730d154a81b44b0e325ccec1f
    3. timeCreated: 1543164717
    4. licenseType: Pro
    5. NativeFormatImporter:
    6.   mainObjectFileID: 100100000
    7.   userData:
    8.   assetBundleName:
    9.   assetBundleVariant:
    With that f62bad9730d154a81b44b0e325ccec1f GUID in hand, I just use a combination of the Posix 'find' and 'strings' and 'grep' tools to pipe prefabs, assets, and scenes through looking for references to that GUID. The 'find' and 'strings' and 'grep' tools exist for every single platform in the world, but they are command line tools and require some learning to get comfortable with, as well as benefit from some shell-script wrappers to make them easier to use.

    And in my Jetpack Kurt project, here would be the sample output of where that prefab is used, which is in two scenes: (and obviously the string shows up in the meta file)

    Code (csharp):
    1. File: ./Prefabs/TrussTower10Assembly_prefab.prefab.meta:
    2. File: ./SpaceFlightContent2/SpaceFlightContent2.unity:
    3. File: ./SpaceFlightFlatGround/SpaceFlightFlatGround.unity:
    All that said, there are in-Unity tools to do all this in a clicky-gui kinda way, just look on the asset store. I just find that sometimes more awkward to use than just running a shell script against a massive repository.
     
    Mitch_Heinsenberg likes this.
  8. bhermer

    bhermer

    Joined:
    Jun 24, 2013
    Posts:
    28
    Thanks for the reply. Yes, I do the same but using Notepad++ thought there may be a super tool out there I was missing :)
     
  9. KokodokoGames

    KokodokoGames

    Joined:
    May 20, 2014
    Posts:
    40
    If your class is getting bigger and bigger, you are probably using the wrong workflow approach. Unity is designed to split up functionality in different scripts and then attach each script separately to the gameobject in the scene.

    Another option is to create classes (NOT partial classes) for functionality that you use. For example, if you have a very complex calculation, you can put that in it's own class. This class is not a MonoBehaviour.

    Code (CSharp):
    1. public class Calculator {
    2.       public float complexCalculation(){
    3.            return 3838.1919;
    4.       }
    5. }
    Now, you can use this complex calculation in other classes:

    Code (CSharp):
    1. public class PlayerScript : MonoBehaviour {
    2.       public void Start() {
    3.             Calculator c = new Calculator()
    4.             float complexNumber = c.complexCalculation();
    5.       }
    6. }
    This is how you could use classes to separate your code. The big advantage is that this calculator is now usable in all your other scripts as well!
     
    Bunny83 and Mitch_Heinsenberg like this.
  10. tonytopper

    tonytopper

    Joined:
    Jun 25, 2018
    Posts:
    199
    Nested types plus partials is great for maintainability.

    Classes can have all sorts of complex things within them that you want scoped within the class, but in a separate file.

    Think about: Struct, IJob, Enum. Partials can also let you store depracated attributes away.

    IMO, it can be a great for productivity and maintainability to split things up into separate files.

    Ofc, you should consider the other options for modularizing your code as well, but saying partials isn't a valid option is advice, in my current opinion, that should be ignored.
     
  11. fwalker

    fwalker

    Joined:
    Feb 5, 2013
    Posts:
    249
    I am having trouble with a partial class that has been moved into "Packages". Has anyone has any trouble with the new Unity package system and partial classes?
     
  12. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    I know that all parts of a partial class have to be in the same Assembly, and obviously in the same namespace (because if they weren't, it's a different class).
     
    Bunny83 likes this.
  13. fwalker

    fwalker

    Joined:
    Feb 5, 2013
    Posts:
    249
    That would do it. Different assemblies... Makes sense that it would have to be the same :)
     
    Kurt-Dekker likes this.
  14. J_Ripley

    J_Ripley

    Joined:
    Oct 14, 2021
    Posts:
    7
    Following this Jason Weimann video on building a 3d game and following his code. Unlike him I could not assign the Bullet.cs file to the bullet. It is in the Unity Script file but says it could not find it and noticed the top has the partial class when I followed him hitting alt Enter where he had the code at the bottom of the Gun.cs to create the Bullet.cs file. I would like to learn this program, not spend 15 days deleting and refollowing his steps trying to understand. Does anyone have an idea what is wrong with it and how to repair it????
     

    Attached Files:

  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Screen Shot 2021-10-25 at 4.05.13 PM.png

    Nothing is going to work as long as it is named with a .txt extension.

    Canonically, C# files should be .cs extension.

    Did you make these files with Notepad perhaps?

    You should right-click in Unity to make the script file, then doubleclick in Unity to open it.

    Notepad should not have anything to do with your code editing process until you are SUPER-familiar with C#.

    If visual studio is misbehaving for you, this may help you with intellisense and possibly other Visual Studio integration problems:

    Sometimes the fix is as simple as doing Assets -> Open C# Project from Unity. Other times it requires more.

    https://forum.unity.com/threads/intellisense-not-working-with-visual-studio-fix.836599/

    Also, try update the VSCode package inside of Unity: Window -> Package Manager -> Search for Visual Studio Code Editor -> Press the Update button

    Also, this: https://forum.unity.com/threads/no-suggestions-in-vscode.955197/#post-6227874
     
    Faremir likes this.
  16. DSivtsov

    DSivtsov

    Joined:
    Feb 20, 2019
    Posts:
    150
    @Kurt-Dekker
    It's not fully true
    All partial class must have the same inheritance, you must not mark the all partial classes with same inheritance (you can set it only for one), but they will have the same inheritance.
    With inheritance of interfaces you fully free, you can set for every partial class is demanded for it interface (your class in summary will realize all these interfaces)
    docs.microsoft.com
     
  17. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Of course they would, it's all 1 class. You can only inherit one class because C# only lets you inherit from one class (no multiple inheritance). Regardless of partial or not.

    All a partial class allows you to do is spread your code for that class across multiple *.cs files. It's an organizational trick. For example the WinForms project in Visual Studio uses partial classes to keep the UI/layout code separate from the logic code via partial classes.

    And this is how interfaces work in C#, regardless of being partial.

    ...

    Now I have my reasons for disliking partial classes.

    But they're more to do with design principles. I find them to clutter things up... if your class is so big that you needed partial classes to make sense of it. Well... maybe your class should be refactored into multiple classes. KISS principal

    I'm also skeptical of Unity. I generally avoid organizational tricks in the language like this due to how Unity relies on the files themselves for figuring a lot of stuff out (scripts when serialized in the editor aren't referenced by class name, but rather by guid. And that guid is associated with the *.cs file, not the class itself. This is why your script filename and classname must match in Unity. And is why Kurt and I both mentioned at least 1 of the files must be named the class file name, to support the way Unity does its magic behind the scenes). While technically it may work... I've been bit in the butt 1 too many times by Unity with such tricks, that I generally just avoid them on top of my already "eh" attitude towards partial classes.

    @Kurt-Dekker and I can disagree on an opinion level, because that's how opinions work.

    But invoking requirements of the C# language and classes at large as anything against partial classes doesn't make sense to me. Those requirements/limitations exist regardless of partial classes.
     
    Last edited: Feb 12, 2022
  18. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Ha! Lord, so funny this thread got necroed just today. I got bit in the butt just yesterday by this when making a camera offsetter control for Jetpack Kurt.

    I made a partial class ScriptableObject first into two files, then three files (I was testing some very-orthogonal ideas), and in the end I removed all the code from the first file and put it all in files 2 and 3.

    As you can imagine, the created ScriptableObject instances were still using the GUID from the original file 1, now gone, making all the ScriptableObjects "Missing Script".

    It was compounded by the fact that I deleted the now-empty file 1 at the time of committing to source control, with Unity closed for commit, then reopened Unity and stuff didn't work.

    It took about 30 seconds of blinking and frowning, then one swig of coffee and I was back in the game.

    In the end, I think the term "partial class" is just a poor term. Yes, the keyword is
    partial
    , but there is nothing partial about the class itself, just each blob of code.

    What could be a better term for partial class?

    - pulled apart class
    - piecemeal class
    - piecemealed class
    - atomized class
    - scattered class
    - dispersed class <--- I like this one!
    - separated class

    The other term is "partial classes..." no such thing exists. You may have many classes that are each implemented using the partial keyword, but at the end of the day, each individual class is what is affected.
     
    lordofduct likes this.
  19. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I like "dispersed" as well.
     
    Kurt-Dekker likes this.
  20. thebarryman

    thebarryman

    Joined:
    Nov 22, 2012
    Posts:
    122
    A good use case for partial classes is when some portion of the class is autogenerated. Microsoft itself does this with Windows Forms.
     
    SisusCo likes this.
  21. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,903
    Please do not necro posts. And it's not the class what's partial, the class definition is partial.
     
  22. thebarryman

    thebarryman

    Joined:
    Nov 22, 2012
    Posts:
    122
    A class is a definition for an object, no? Not sure what you mean by distinguishing between a partial class and partial "class definition."
     
  23. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,903
    That's just one aspect of a class. They also contain and own static members and methods. They are special objects can be used as blueprints to instantiate objects of their type. Class definition is the text you read when you see
    public partial class
    or similar. The
    partial
    keyword tells you that this class definition is incomplete. It's partial.
     
  24. thebarryman

    thebarryman

    Joined:
    Nov 22, 2012
    Posts:
    122
  25. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,124
    You're subdividing the definition of the class. When you compile your project all of the partial class definitions are combined into one single definition and then compiled into an assembly. It's literally in the first paragraph of that link.

    upload_2023-10-6_20-18-35.png

    The .NET runtime isn't even aware of the concept as it only ever sees a single class assembly.

    https://stackoverflow.com/questions/31685912/partial-class-in-a-separate-assembly
    https://stackoverflow.com/questions/3858649/partial-classes-in-separate-dlls

    That said "partial class" is much less of a mouthful than "partial class definition", and since it's just the definition that is partial it's easier to just not say it so most people refer to it as the former even though it's technically the latter.

    Subdivided?
     
    Last edited: Oct 7, 2023
  26. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,114
    I don't really see how drawing this distinction is that important. Even Microsoft's official documentation uses terminology like "splitting a class - - over several files". It feels a little bit like "This is not a pipe" type philosophical meandering :D

    But I guess if you have a strong mental model about the class itself only coming into existence once the application has been compiled, talking about "splitting a class" can sound unintuitive.