Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
0
Question by NeatWolf · Dec 10, 2016 at 05:13 PM · classsingletonextension-methods

Writing an extension method for a class. Is it possible? How?

Hi,

I wrote this piece of code to speed up checking existance of singletons without actually changing the singletons implementation and without of course checking their Instance property or the non-accessible _instance private static variable.

 using UnityEngine;
 using System.Collections;
 
 public static class FNSUtils {
     public static bool ExistsInSceneOrError(this System.Type type)
     {
         if (GameObject.FindObjectOfType(type) != null)
             return true;
         else
         {
             Debug.LogError("Couldn't find a " + type.ToString() + " in the scene. Add it, save the scene and reload it");
             return false;
         }
     }
 }
 

In this way I could simply do a check like GameManager.ExistsInSceneOrError() and return a value, without the hassle to write this for every Manager or Singleton.

But, it doesn't seem to work.

Now, is there a way to do this with the method extensions? Which other solution would you propose? A static utility class with a static method?

Comment
Add comment · Show 7
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 Bieere · Dec 11, 2016 at 09:56 PM 0
Share

I assume you've tried: GameObject.FindObjectOfType(typeof(type))

avatar image NeatWolf Bieere · Dec 11, 2016 at 10:58 PM 0
Share

Sure, the problem is not the feasibility, but the need to provide a generic and easy to use shortcut to that, since I also have to do some checks.

It's a piece of code I'd have to rewrite over and over.

Calling myClass.ExistsInSceneOrError() is much cleaner.

Any idea on how to make it work? Am I missing something?

avatar image Glurth · Dec 12, 2016 at 06:00 AM 0
Share

"But, it doesn't seem to work." Need more details. Looks ok to me, at fist glance. Is it the FindObjectsOfType that fails?

Alternatives: Create a Static Class that contains a Dictionary - and have your singletons register themselves in there. Then when you need to check for existence, it should be a much shorter list to look through than all scene objects, and you can just use dictionary.Contains to see if it exists. Though I'd also return the looked-up gameobject or null, rather than a bool.

avatar image NeatWolf Glurth · Dec 12, 2016 at 08:53 AM 0
Share

Thanks, but as I said, I'm not looking for alternative solutions, I'm already using one in the meantime.

Nothing fails, the compiler works just as fine as long as I don't try to use it.

Simply, when typing the name of any class and pressing period, the autocomplete fails to suggest me the extension method, and typing it results in a "class doesn't contain such field or method" compile error.

avatar image hexagonius NeatWolf · Dec 12, 2016 at 04:41 PM 0
Share

i know you said no alternatives, but it won't work with an extension method and a faster way would be a generic singleton with that method at its core using T

Show more comments

3 Replies

· Add your reply
  • Sort: 
avatar image
2

Answer by Glurth · Dec 12, 2016 at 05:00 PM

Well, the way you have it defined now, no ..

 SomeClass.ExistsInSceneOrError()

will NOT give you access to this function. Note, you are NOT extending "SomeClass", you are extending System.Type. However,

 typeof(SomeClass).ExistsInSceneOrError()  

SHOULD work, because the typeof() function will return a Systsem.Type variable.

Consider the extension method:

  static void func(this Object o)

Object o, must be an INSTANCE of a variable. There is no way to specify a TYPE as input in a regular parameter. Sure, you can use System.Type, but this will ALSO require and instance of a variable (of class System.Type), (which in the code above, is instantiated by typeof() ).

Extension methods are simply not meant to provide the syntax you are looking for BECAUSE they take as input; variable instances, not types.

Instead of Extension function, you could use Generics and Inheritance to get the syntax you want:

 public abstract class SingletonBase<T>:MonoBehaviour where T: SingletonBase<T>
 {
     public static bool ExistsInSceneOrError()
     {
         if (GameObject.FindObjectOfType(typeof(T)) != null)
             return true;
         else
         {
             Debug.LogError("Couldn't find a " + typeof(T).ToString() + " in the scene. Add it, save the scene and reload it");
             return false;
         }
     }
 }
 
 class SingletonOne : SingletonBase<SingletonOne> //formerly :Monobehavior
 {
     //no change
 }
 
 class SingletonTwo : SingletonBase<SingletonTwo>  //formerly :Monobehavior
 {
     //no change
 }

usage:

 SingletonTwo.ExistsInSceneOrError();



Comment
Add comment · Show 9 · 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 NeatWolf · Dec 12, 2016 at 05:10 PM 0
Share

You're right! It works! Thanks!

I actually don't need it to work on System.Type but on a generic class (even if I have to use it on $$anonymous$$onoBehaviour only).

Would that change the calling syntax to avoid that ugly typeof?

What would you change to make it work on a generic class or $$anonymous$$onobehaviour? Would it still be possible?

avatar image Glurth NeatWolf · Dec 12, 2016 at 05:13 PM 1
Share

I think the way you probably want to go is with a simple Generic function(https://msdn.microsoft.com/en-us/library/twcad0zb.aspx), rather than extension function:

 public static bool ExistsInSceneOrError<T>()
      {
          if (GameObject.FindObjectOfType(typeof(T)) != null)
              return true;
          else
          {
              Debug.LogError("Couldn't find a " + typeof(T).ToString() + " in the scene. Add it, save the scene and reload it");
              return false;
          }
      }

Call using

 FNSUtils.ExistsInSceneOrError< SomeClass >();


edit/addition: I've only used it on generic CLASSES myself, so I don't know if the following works for generic functions too. You can limit availability of your T parameter, to only certain classes, that fullfill particular requirements, by using the WHERE keyword: https://msdn.microsoft.com/en-us/library/d5x73970.aspx

e.g. to make it work ONLY on monobehaviors

 public static bool ExistsInSceneOrError<T>() where T: $$anonymous$$onobehavior

TESTED: this DOES work- and will make the compiler generate an error if we now try to call say... FNSUtils.ExistsInSceneOrError< int >(); since "int" is not a $$anonymous$$onobehavior

avatar image NeatWolf Glurth · Dec 12, 2016 at 06:11 PM 0
Share

Generics are a nice idea.

So I tried to change the extension using generics as well (this is definitely a thing I've never tried before):

     public static bool ExistsInScene<T>(this T t)
     {
         if (GameObject.FindObjectOfType(typeof(T)) != null)
             return true;
         else
         {
             Debug.LogError("Couldn't find a " + typeof(T).ToString() + " in the scene. Add it, save the scene and reload it");
             return false;
         }
     }

but of course I was expecting some weird syntax, but in the end I still have to call it as

 typeof(class).ExistsInscene();

I'm probably missing something

Again, I tried:

     public static bool ExistsInScene<T>(this T t) where T:Object
     {
         if (GameObject.FindObjectOfType(typeof(T)) != null)
             return true;
         else
         {
             Debug.LogError("Couldn't find a " + typeof(T).ToString() + " in the scene. Add it, save the scene and reload it");
             return false;
         }
     }


but the calling syntax would be:

 (FNSScene$$anonymous$$anager as Object).ExistsInScene()

now if I only was able to use some keyword to force typecasting in the fields of the method, such as "coerce", used in other languages...

Show more comments
Show more comments
avatar image Glurth NeatWolf · Dec 13, 2016 at 05:49 PM 1
Share

FYI: updated answer with an example to generate the syntax you are looking for.

avatar image NeatWolf Glurth · Dec 14, 2016 at 10:15 AM 0
Share

Thanks, but the premise was to use the extension system without touching the singleton code, as per OP.

Definitely, implementing it this way was the most straightforward method to have that syntax working.

Show more comments
avatar image
1

Answer by JoshuaMcKenzie · Dec 15, 2016 at 08:32 AM

You can use Extension Methods just fine. its definitely possible.

 public interface ISingleton{} // marker interface
 public static class SingletonExtensions
 {
     private static Dictionary<System.Type,UnityEngine.Object> singletons = new Dictionary<System.Type, UnityEngine.Object>();
 
     public  static bool SingletonExists<T>(this Component component)
         where T:UnityEngine.Object
     {
         return GetSingleton<T>()!=null;
     }
     public  static T GetSingleton<T>(this MonoBehaviour script)
         where T:UnityEngine.Object
     {
         T singleton = GetSingleton<T>();
         if(singleton == null)
         {
             Debug.LogErrorFormat(script,"Singleton {0} not found!",typeof(T));
         }
         return singleton;
     }
     public  static T GetSingleton<T>(this ScriptableObject script)
         where T:UnityEngine.Object
     {
         T singleton = GetSingleton<T>();
         if(singleton == null)
         {
             Debug.LogErrorFormat(script,"Singleton {0} not found!",typeof(T));
         }
         return singleton;
     }
     public  static void LoadSingleton<T>(this ISingleton script)
         where T:UnityEngine.Object,ISingleton
     {
         T singleton = GetSingleton<T>();
         if(singleton == null)
         {
             Debug.LogErrorFormat(script,"Singleton {0} not found!",typeof(T));
             return;
         }
         script = singleton;
     }
 
     private  static T GetSingleton<T>()
         where T:UnityEngine.Object
     {
         UnityEngine.Object singletonObject = null;
         System.Type type = typeof(T);
 
         singletons.TryGetValue(type, out singletonObject);
 
         if(singletonObject != null) return (T) singletonObject;
 
         T singleton = UnityEngine.Object.FindObjectOfType<T>();
 
         if(singleton == null)  return null;
 
         singletons[type] = singleton;
         return singleton;
     }
 }

You can also have it reference the singleton itself as the caller. a little known fact about extention methods is that the instance running the extension can be null so something like this

 ISingleton gameController = null;
 gameController.LoadSingleton<GameController>();

can work even if gameController was null when the extension method was called.

the question of "Should you use Extension methods for this?" however is debatable.

Comment
Add comment · Show 1 · 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 NeatWolf · Dec 15, 2016 at 08:06 PM 0
Share

I definitely agree I should be using other ways to accomplish this (and I actually am using a good compromise), but I thought it would still be an interesting subject to have an answer for :) Or at least brainstorm a bit around it. I think corner cases are always interesting to explore.

avatar image
0

Answer by jenci1990 · Dec 15, 2016 at 07:07 PM

Your code is good. Try use like this:

 public static class FNSUtils {
     public static bool ExistsInSceneOrError(this System.Type type) {
         if (GameObject.FindObjectOfType(type) != null)
             return true;
         else {
             Debug.LogError("Couldn't find a " + type.ToString() + " in the scene. Add it, save the scene and reload it");
             return false;
         }
     }
 }

And use:

 typeof(AnyClassName).ExistsInSceneOrError();


Comment
Add comment · Show 1 · 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 Bunny83 · Dec 15, 2016 at 07:49 PM 0
Share

Uhm, you just copied the original code into your answer. How does that answer the question?

If you just wanted to show how to use it, you're 3 days late. Glurth already showed that.

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

63 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 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 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

Problem with Singleton and NullReferenceException? 0 Answers

Serialization of Singleton vs Static class in Editor 1 Answer

StartCoroutine by another class (Coroutine inside Coroutine - Instance class) 1 Answer

javascript singleton 1 Answer

How to sum a property of a class in a List 2 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