public static T Clone<T>(T source) where T : class, IEnumerator
{
var sourceType = source.GetType().UnderlyingSystemType;
var sourceTypeConstructor = sourceType.GetConstructor(new Type[] { typeof(Int32) });
var newInstance = sourceTypeConstructor.Invoke(new object[] { -2 }) as T;
var nonPublicFields = source.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
var publicFields = source.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in nonPublicFields)
{
var value = field.GetValue(source);
field.SetValue(newInstance, value);
}
foreach (var field in publicFields)
{
var value = field.GetValue(source);
field.SetValue(newInstance, value);
}
return newInstance;
}
And test to use it this way:
IEnumerator MyMethod ( int para )
{
print("got=" + para );
yield return 0;
}
void Start()
{
IEnumerator clone = Clone( MyMethod(15) );
}
But I get a NullReferenceException : Object not set to an instance of an object at the line:
var newInstance = sourceTypeConstructor.Invoke(new object[ ] { -2 }) as T;
I never used Reflection and I don’t know how to handle this.
And maybe, if by the way there is a solution to clone or create a new instance from the original IEnumerator, I’m okay to hear it.
Thanks in advance guys
EDIT → ANSWER at the bottom of the page from @JohnnyA :
that method doesn’t have to be generic seeing as you don’t really use the generic for anything. You could just accept IEnumerator as the parameter, and return an IEnumerator.
If you have the function, why not just create a new instance of it by calling the method again? This would effectively be a clone.
Your function appears to be for cloning a generic object by reflecting out and copying its fields (there’s an added issue with the implementation because the reflection done does not account for any private fields of the types this object inherits from… the bindingflags used do not account for those.). This is an issue seeing as the ‘iterator function’ you’re cloning doesn’t really have much for fields representing its state. It’s a bit more complex than that.
Because ‘iterator methods’ do not implement the ‘Reset’ method of the IEnumerator interface (it throw an exception), any clone of an iterator method would a) not get any of the first entries in the enumerator that you have already moved over and b) you’d waste up the enumerator in the cloning process (operating all parts of the code in the iterator method).
tldr; - number 2 is the most important. Why are you even doing this? Just call the method again, a whole new iterator is created.
Actually it works, but I wasn’t specific enough. I actually import my method from a method parameter, and then use it to add a listener to a button click like so:
If I change the delegate for this:
gameObject.GetComponent(Button).onClick.AddListener( delegate() { var tempIEnum = myAction; StartCoroutine( tempIEnum ) } );
Since the IEnumerator is consumed. I’d like to use the clone in the delegate each time it is called. But, as I said atthr beginning, I’m open to other solutions. The only thing is that I want to preseve the way the Action Method is called: Action ( MyMethod(12) ). And not passing lambdas inside the Action argument.
Yep, it would work. But as I said in my previous post I want to keep the simple syntax AddAction( Method(15) ) and put the complex part into the AddAction Method. I know it seems a stubborn way of thinking, but it’s to simplify the repetitive use of AddAction. Even if it’s imply not so efficient way of scripting behind the scene since it’s just call at click and not in update.
If someone have any idea to make it happen, it would definetely make , at least, my month!
I understand it and apreciate your help. But I can’t imagine that it’s not doable! I mean, the easy way to pass the function. Maybe passing an IEnumerator is not the best way. But I tried everything, passing a Func<IEnumerator, int>, but neither got it to work. I’m stuck on this one for days and now I wait for a messiah.
Here’s another option. You can create a delegate that represents a coroutine. I do this for other things, and you could use it as well. The delegate is basically this:
Downside is that this doesn’t support paramters. What we can do for that is:
Have a generic CoroutineMethod (similar to System.Action with generic inputs)
public delegate IEnumerator CoroutineMethod<T>(T param);
public delegate IEnuemrator CoroutineMethod<T1,T2>(T1 param1, T2 param2);
... so on so forth
And
void AddAction(System.Delegate routine, object[] args)
{
gameObject.GetComponent<Button>().onClick.AddListener(() => {
var e = routine.DynamicInvoke(args) as IEnumerator;
if(e != null) StartCoroutine(e);
}
}
void Start()
{
AddAction(new CoroutineMethod<int>(MyMethod), new object[]{15});
}
Really though… I find all these interfaces to be dirty. Where as the nice simple Action based one is a clean interface. I don’t see what’s so not “clean” about:
Your original question about cloning an IEnumerator that was created from an iterator method… sorry, no, it can not be cloned. It’s not the way that the iterator method works in .net/mono.
Well, I didn’t play wih Delegate passed through method. Interesting. But yep definetely not helping the syntax. Too bad…
And to be clear, I’m not really saying that the use of lambdas is not clean, but not easy to understand regarding the syntax for the beginners, which is what the script I’m trying to do is for.
For now, if I can’t find any other way, which I would prefer not, is to pass as I said, an Func < object, Ienumerator> + a second object argument.
So the call will be something like this : AddAction( MyMethod, 12 ); But this imply defining lots of AddActions with diferents objects like int, float, string, Component, etc.
But yep, as your last post says, the question was about cloning an IEnumerator, and aparently it’s not doable…! Thanks for your help
As you can see a special class type is created, and the instance of it is a fairly complex object. The cloning of which is difficult. Especially since the state of it is stored in its fields. So a clone wouldn’t revert back to the start of the enumerator, but instead preserve the current state.
Yep, I’ve been through this post ( Ben Maddox point it out when answering the stackoverflow link I posted ). But as hard as I tried to understand, I didn’t got a fairly bit of anything hapenning here. I’m a self taught young developper and this thing exceeds by far my knowledge!
Still though I find this convoluted. A simple example in the documentation demonstrating how to pass in a coroutine doesn’t seem to hard. It also means that people like me who have a custom ‘RadicalCoroutine’ also have support to. I don’t call Coroutines directly, instead I call an extension method called ‘StartRadicalCoroutine’.
Thanks for this I’ll look at this. specificaly since it looks usefull for AI implementation. Though, again, and you can throw a rock at me for being stubborn, if I understood it well, user should call your delegate like so AddAction( this.MyMethod, 12);
Which is already to complicated and where I prefere passing a Func<object, IEnumerator> as I showed few messages ago.( where the syntax would be AddAction( MyMethod, 13). Even if I have to define shit loads of different possible parameters type :p.
And for the last thing you pointed out, the flexibility regarding actual user own implements compatibility. The script will defenitely be for beginners and will probably not match the needs of advanced programers!