• 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 Lahzar · Dec 22, 2015 at 03:30 PM · coroutinereflectionienumeratornameexists

Get IEnumerator from name or convert MethodInfo to IEnumerator

Title says it all: I am stuck on how I can return/store an IEnumerator, when I can only access its name. So I have a string, w$$anonymous$$ch is its name, and I want to end up with an IEnumerator.

I already know it exists, as I am getting the name of the coroutine from MethodInfo, but I need to store it for later use, and not start/invoke it!

EDIT: More info in comments

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

2 Replies

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

Answer by wibble82 · Dec 22, 2015 at 03:39 PM

Hi there

OK! After lots of comments below, I'm going to update t$$anonymous$$s answer. What I originally wrote is still pretty relavent, so here it is in italics:

Calling the function returns the IEnumerator that unity uses to run your coroutine. You can call functions using method info using 'invoke': https://msdn.microsoft.com/en-us/library/a89hcwhh(v=vs.110).aspx So if you have the MethodInfo, you can call the function whenever you want. T$$anonymous$$s will return an IEnumerator object. The IEnumerator object is simply the C# means to provide 'yield' functionality - i.e. a function that can execute in steps, yielding periodically. When you pass the IEnumerator to StartCoroutine, t$$anonymous$$s simply hands it off to unity. Internally it creates a coroutine object, from w$$anonymous$$ch it repeatedly calls the enumerator until it finishes.

Now, onto the meat.

After lots of back and forth, my understanding of your problem is that, through whatever means, you have a function (you called ClassC) that currently has (or at least can be provided):

  • The name of a function from another class that returns an IEnumerable

  • Through reflection, you have got the MethodInfo for that function

  • You also say you have the 'script' it is on. Hopefully by that you mean the 'instance' of the script?

You have these 3 bits of info, because you want to extend the capabilities of unity's coroutine system to allow for pausing.

Your approach to t$$anonymous$$s, w$$anonymous$$ch seems perfectly reasonable, is to create 1 generic unity coroutine that 'wraps' the calling of a 'coroutine function' provided by another class. Your generic coroutine function has pausing built in. T$$anonymous$$s was your example, w$$anonymous$$ch I've not tested but seems reasonable:

 public IEnumerator RunRoutineManually() 
 {
     w$$anonymous$$le (true)    
     {
         if (!routineIsPaused) 
         { //Imagine t$$anonymous$$s is a bool controlled by ClassB
             if (routineHasStopped)
             { //T$$anonymous$$s aswell
                 routine.Reset();
                 Destroy(t$$anonymous$$s.gameObject);
                 yield return false;
             }
  
             yield return null;                      //Coroutine is paused!
         }
  
         routine.MoveNext();
         yield return routine.Current;
     }
 }

The question you are asking is: So I have my function name, my MethodInfo and my 'script', but my 'generic coroutine' needs an IEnumerator. Where the do I get it?!

So, to ac$$anonymous$$eve your goal, all you actually need are:

  • The MethodInfo of your 'coroutine function'

  • The instance on w$$anonymous$$ch you want to run the coroutine - i.e. if the function is defined as part of ClassB, you will need the instance of classB on w$$anonymous$$ch you wish to run it. Hopefully t$$anonymous$$s is what you meant by 'I have the script'

To explain t$$anonymous$$ngs in detail, first I want to make sure you understand some bits and pieces (sorry if you already know t$$anonymous$$s stuff!):

First, I've being saying 'coroutine function' so far, but there's really no such t$$anonymous$$ng! T$$anonymous$$s, is not a coroutine:

 public IEnumerator YieldReturnSomeBooleans() 
 {
     yield return false;
     yield return false;
     yield return false;
     yield return false;
     yield return false;
     yield return true;
 }

And neither is RunRoutineManually(). They are Enumerators. i.e. they are functions that the .net library uses to implement stuff like 'foreach' loops. Their critical property is that they can 'yield', return a result, and then be told to 'carry on', all by calling functions on the IEnumerator that they return. T$$anonymous$$s I t$$anonymous$$nk you already understand.

Entirely independently, unity also implements a system called 'coroutines', w$$anonymous$$ch some languages would call 'fibres'. T$$anonymous$$s system allows you to create functions that run independently of the stuff like 'Update', and have the ability to yield, then carry on next frame.

Naturally, the engineers at Unity decided the best way to expose coroutines to users was through Enumerators, because they provide the mechanism for writing a function that can yield, then be told to carry on. As a result we end up with the function:

 StartCoroutine(IEnumerator coroutine)

There is also a version that takes a string, but that's just a utility and I want to ignore it for now!

You use the unity system by calling your Enumerator function, and passing the IEnumerator it returns into StartCoroutine. From there Unity takes over, calling 'MoveNext' on the enumerator you provide it once per frame (or in other ways depending on what you return from it).

So:

 StartCoroutine(YieldReturnSomeBooleans());

Could be written:

 IEnumerator myenum = YieldReturnSomeBooleans();
 StartCoroutine(myenum);

Or if the coroutine function was part of another object, you could write:

 IEnumerator myenum = otherobject.YieldReturnSomeBooleans();
 StartCoroutine(myenum);

Similarly, you could store that 'myenum' value somewhere, pass it around, and later on call StartCoroutine.

Now, assuming you have your methodinfo and the instance on w$$anonymous$$ch you want to call it, you can do exactly the same as above. However instead of calling the YieldReturnSomeBooleans function directly, you can 'invoke' it via reflection:

 //I assume you have these somewhere?
 MethodInfo mymethodinfo = ?;
 object myobject = ?;
 
 //invoke the method that we know returns an IEnumerator on myobject, passing an array of 0 paramaters
 IEnumerator myenum = (IEnumerator)mymethodinfo.Invoke(myobject, new object[]{});
 
 //now start it as usual
 StartCoroutine(myenum);

So, going all the way back to your original function:

 public IEnumerator RunRoutineManually() 
 {
     //these are the values you presumably are storing in 'ClassC' now - not 'routine'
     MethodInfo mymethodinfo = ?;
     object myobject = ?;
 
     //we get 'routine' through invoke
     IEnumerator routine = (IEnumerator)mymethodinfo.Invoke(myobject, new object[]{});
 
     //everyt$$anonymous$$ng else is just as you wrote it
     w$$anonymous$$le (true)    
     {
         if (!routineIsPaused) 
         { //Imagine t$$anonymous$$s is a bool controlled by ClassB
             if (routineHasStopped)
             { //T$$anonymous$$s aswell
                 routine.Reset();
                 Destroy(t$$anonymous$$s.gameObject);
                 yield return false;
             }
  
             yield return null;                      //Coroutine is paused!
         }
  
         routine.MoveNext();
         yield return routine.Current;
     }
 }

I hope that very long explanation was for the right t$$anonymous$$ng. If not, hopefully it gets you on the right path.

-Chris

p.s. I haven't tested that code, so there might be a few compile errors. It's along the right lines though.

Comment
Add comment · Show 3 · 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 Lahzar · Dec 22, 2015 at 05:11 PM 0
Share
avatar image wibble82 Lahzar · Dec 22, 2015 at 05:42 PM 0
Share
avatar image Lahzar wibble82 · Dec 22, 2015 at 08:35 PM 0
Share
avatar image
0

Answer by jmonasterio · Dec 22, 2015 at 07:04 PM

Perhaps see:

http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know

In the article it mentions:

Your coroutine can yield one of these in order to wait for another coroutine to finish before resuming execution.

W$$anonymous$$ch sounds like what you said you want to do (in comments).

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 Lahzar · Dec 22, 2015 at 08:43 PM 0
Share

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

33 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

Related Questions

How can you tell if a gameobject is looking directly at another gameobject? 1 Answer

WaitForSeconds Not Working 4 Answers

Problem with coroutine 2 Answers

How Return Or Restart A Coroutine When A Variable Increase? 1 Answer

Does coroutines are affected by Time.timeScale? 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