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 jmgek · Feb 24, 2017 at 09:39 PM · reflectioninvokeactiondelegates

How can I invoke a Method Property from a MethodInfo (Reflection) while keeping it's properties and types generic?

 public class MyComponent{
      void MyBoolClass(bool value){};
      void MyFloatClass(float value){};
      float MyReturnFloat(){return 1f;};
 }

 private Action myAction = ()=>{};
 public MyComponent myComponent;
 void Start()
 {
     MethodInfo methods = myComponent.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

     //I will want to create a list later, just using the first index as a code example
     myAction = (Action)Delegate.CreateDelegate(typeof(Action), this, methods[0]);
     //Currently getting an Exeption
  }

I am trying to invoke a method from an array of methods but I running into a problem, how would I go about using dynamic generic properties? In the example how am I able to create an action to handle the MyBoolClass and MyFloatClass?

Thanks guys!

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
0

Answer by Bunny83 · Feb 25, 2017 at 12:16 AM

Your question doesn't make much sense. You have a delegate type that takes no parameters and has no return type. All your methods either have a parameter or return a value. Those methods have completely incompatible signatures. There is no "generic" delegate type that can be directly used. A generic type like Action<T> requires a type argument Action and Action<T> are also completely incompatible to each other.

What exactly are you trying to achieve? If you want "somehow" assign "MyBoolClass" or "MyFloatClass" to an Action delegate you would need a closure that includes the parameter.

For example you would need a class like this:

 public class BoolClosure
 {
     public bool parameter;
     public System.Action<bool> method;
     public BoolClosure(MethodInfo aMethod, object aObj, bool aParameter)
     {
         var t = typeof(System.Action<bool>);
         method = (System.Action<bool>)System.Delegate.CreateDelegate(t, aObj, aMethod);
     }
     public void Execute()
     {
         method(parameter);
     }
 }

Usually closure classes are generated by the compiler automatically. However since you want to create them dynamically you have to create them yourself.

You can use it like this:

 MethodInfo method = myComponent.GetType().GetMethod("MyBoolClass", BindingFlags.Instance | BindingFlags.NonPublic);

 myAction = new BoolClosure(method, myComponent, true).Execute;

Now when you invoke myAction like this:

 myAction();

You will actually invoke the method "MyBoolClass" with the parameter "true". What we just manually created actually happens when you do something like:

 myAction = ()=>myComponent.MyBoolClass( true );

Though we still don't know what you actually want to do. You should add more information on your background. For what purpose would you need this?

Comment
Add comment · Show 2 · 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 jmgek · Feb 25, 2017 at 12:53 AM 0
Share

Hey bunny thanks for the reply, as for my question I am asking how I can achieve this, I understand my delegate takes in no parameters and has no return type that is why I started this question.

As for the information I am trying to invoke methods (On unity components) dynamically through reflection. Example: Light component contains [Intensity] that accepts a float, I need to create a generic action to pass floats, Light also contains set active that accepts a bool, I need to create a generic action to pass a bool.

I am using reflection to populate an array of methods (I don’t fully understand why you’re telling me to use .get$$anonymous$$ethod(), I’m not using get$$anonymous$$ethod(), I am using get$$anonymous$$ethods(), that returns an array of methods, this is where the dynamic part comes in): $$anonymous$$ethodInfo methods = myComponent.GetType().Get$$anonymous$$ethods() from that array I want to be able to invoke the methods that are in the component class that I assigned to myComponent, I need the missing explanation as to how I can invoke [methods] in this case dynamically since I don’t know how I can specify a generic return type or parameter, and I don’t know if it’s possible or not.

$$anonymous$$y guess is something like to put it in quasi pseudo code: myAction = (Action<T>)Delegate.CreateDelegate(typeof(Action<t>), this, methods[i]);

Thanks again, let me know if this makes sense.

avatar image Bunny83 jmgek · Feb 25, 2017 at 02:08 AM 0
Share

As i said you can not have a delegate variable that can hold different delegate types. .NET / $$anonymous$$ono is a strongly typed environment. So you can't treat completely different methods in a generic manner. The only exception is reflection. So store your $$anonymous$$ethodInfo and the object reference which contains the method. You can always directly invoke a $$anonymous$$ethodInfo

 methods[0].Invoke(myComponent, new object[] { true });

Instance methods require the object instance as first parameter. All actual method parameters has be be passed to Invoke as an object array. In this case i pass "true" to the method. $$anonymous$$eep in $$anonymous$$d whenever the type you pass doesn't match the type of the method signature your code will throw an exception and is ter$$anonymous$$ated.

btw: I used Get$$anonymous$$ethod because i wanted to post a working example. You for example didn't declare your "methods" variable as array. Also my example only works when the signature matches. You can't create a delegate in a generic manner. A delegate variable has to have a distinct type at runtime.

You may not fully understand what a generic type actually is. It doesn't mean it can simply take a dynamic type. It's just a way to avoid having to write the same code several times. To actually use a generic type you have to create a "concrete type" out of the generic type in order to use it. Action<bool> is a concrete type. Action<> is the generic type. Again, the generic type can't be used at runtime. It can only be used with reflection to construct a concrete type ($$anonymous$$akeGeneric$$anonymous$$ethod / $$anonymous$$akeGenericType).

You still haven't sait how you actually want to use this. Again storing completely different things in an array makes no sense since they can't be treated similar as they aren't similar at all.

ps: I just had another look at your question. The "this" in this line makes no sense at all:

 myAction = (Action)Delegate.CreateDelegate(typeof(Action), this, methods[0]);

You have to pass the object instance reference to CreateDelegate. So the object that actually contains that method which is in your case your "myComponent" object and not the object that contains your Start method.

avatar image
0

Answer by hrgchris · Feb 25, 2017 at 07:26 AM

Hi there

Instead of trying to store an action created by CreateDelegate (which is strongly typed), store the MethodInfo. Then use MethodInfo.Invoke to call the method, which just takes a set of objects as arguments and should do the conversions/ type checking internally.

Generally the CreateDelegate is there as a tool for when you specifically need to get a way of calling the code without reflection such as attaching it to an event, or passing into other code that doesn't handle reflection. As you can imagine, this naturally imposes the strongly typed properties of c#, so at that point you lose the ability to ignore types.

Chris

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 Bunny83 · Feb 25, 2017 at 02:50 PM 0
Share

Within .NET / $$anonymous$$ono you can never "ignore types", even when using reflection. If a method requires a string parameter you have to pass a string as argument. You can / have to do it in a dynamic way, but it doesn't provide any more flexibility. It just adds more potential for mistakes which lead to runtime errors. Invoke doesn't do any type conversion. If you feed the wrong parameter types it will throw an exception. That includes types that are usually implicitly converted in C# code.

A common example would be valuetypes. Everybody knows you can cast an int into a float (even implicitly). Though when dealing with value types in a "more generic way" (storing it as "object") you can't directly cast an int into a float. Example:

 int i = 5;
 object o = i;
 float f = (float)o; // error here

 float f = (int)o; // this works

Likewise the other way round

 float f = 5f;
 object o = f;
 int i = (int)o; // error here
 
 int i = (int)(float)o; // this works

You would have use the System.Convert class to directly convert a boxed value type into another type:

 int i = System.Convert.ToInt32(o);

Though the Convert class can also only do any conversions that you can do with the actual types. The most "generic" way when dealing with reflection would be System.Convert.ChangeType which can convert an object value into another type that is provided as System.Type. But again, it can only convert things that are actually convertable.

That means if you plan to use reflection to get a list of unknown methods you would need to do a lot of analyzing of it's parameter types in order to actually invoke it. Generic methods (like GetComponent<T>) will give you even more headache as you first have to construct a non-generic methodinfo out of the generic one by providing the generic type parameter info.

And that's why i ask for what exact purpose he needs this. It simply makes no sense to treat arbitrary methods with completely different signatures in a generic way because you can not simply "call them".

avatar image hrgchris Bunny83 · Feb 25, 2017 at 03:33 PM 0
Share

Ummm.. Ok. Not sure I disagreed with any of that, but hey ho.

Like I say, if you want to avoid storing bespoke delegates for every potential argument, store the method infos and use Invoke. my few cents.

avatar image Bunny83 hrgchris · Feb 25, 2017 at 05:38 PM 0
Share

Yes, that's what i already mentioned in my comment above 14 hours ago ^^.

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

66 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 avatar image avatar image avatar image

Related Questions

How do I get the system type of Mathf in JS ? 1 Answer

Finding a method by custom attribute and passing to a UI button 1 Answer

Casting methods, events, and/or delegates from strings / enum 0 Answers

EventManager with parameters 1 Answer

Reflection - passing parameters to an invoked function 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