Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 Pharaoh_ · Apr 09, 2015 at 12:02 PM · lambda

Dictionary, Lambda expression & Action<,>

Hey,

I am trying to pass Dictionary entries as method calls. Currently, a member on these boards suggested I used System.Action, which is great for methods that don't take any parameters. In my case, my methods have parameters.

I am creating a Dictionary in order to check what is going to happen upon collision of two objects, instead of using an extensive switch. Thus, I have an IEnumerator which checks the distance between the two objects. Once it exits, it will invoke the appropriate method, by making a match from the string I am passing. This string is then matched with the Dictionary's entries and invokes the corresponding method.

     private Dictionary<string, System.Action> moveUnitActions = new Dictionary <string, System.Action> ();
 
     public void RemoveUnit (GameObject whichUnit) {
         Destroy (whichUnit);
     }
 
     public IEnumerator MoveUnitTowardsUnit (GameObject whichUnit, GameObject whereTo, float speed, string collisionEvent) {
         while (Vector3.Distance (whichUnit.transform.position, whereTo.transform.position) > 15f) {
             whichUnit.transform.position = Vector3.MoveTowards (whichUnit.transform.position, whereTo.transform.position, Time.deltaTime * speed);
             yield return null;
         }
         //block that checks for the proper action
     }
 
     moveUnitActions ["destroy"] = () => RemoveUnit(); //PROBLEM here.

I am aware that the line indicated as "PROBLEM here." is wrong. I tried so many different syntax combinations with lambda expressions that I no longer remember the original. In order to point the "destroy" entry to the RemoveUnit() method, I need a GameObject argument (because this is how the said method works). However, the gameobject will vary, depending on the unit I wish to destroy.

According to what I have seen, there are also Func and Action, with which I am not experienced. Is Action indeed the answer to my problem here and how do I modify the lambda expression? Finally, how will I invoke the method, once I find a match in the Dictionary? As simple as RemoveUnit(myUnit);?

Cheers :)

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
1
Best Answer

Answer by DoTA_KAMIKADzE · Apr 09, 2015 at 12:39 PM

I guess you want something like that?:

 public void RemoveUnit(GameObject whichUnit)
 {
     Destroy(whichUnit);
 }
 private Dictionary<string, System.Action<GameObject>> moveUnitActions = new Dictionary<string, System.Action<GameObject>>();
 private void populate()
 {
     moveUnitActions["destroy"] = RemoveUnit;
 }
 public void helloWorld()
 {
     GameObject obja = new GameObject();
     //make sure that you have populated your dictionary before calling that:
     moveUnitActions["destroy"](obja);
 }

P.S. Here is an example for your updated question:

     public void RemoveUnit(object whichUnit)
     {
         Destroy((GameObject)whichUnit);
     }
     private int someInt = 0;
     public void AddIntegerAndPostString(object pass)
     {
         Tuple<List<int>, string> iInt = (Tuple<List<int>, string>)pass;
         foreach (int o in iInt.Item1)
         {
             someInt += o;
         }
         Debug.Log(iInt.Item2);
     }
     private Dictionary<string, System.Action<object>> moveUnitActions = new Dictionary<string, System.Action<object>>();
     private void populate()
     {
         moveUnitActions["destroy"] = RemoveUnit;
         moveUnitActions["addPrint"] = AddIntegerAndPostString;
     }
     public void helloWorld()
     {
         GameObject obja = new GameObject();
         //make sure that you have populated your dictionary before calling that:
         moveUnitActions["destroy"](obja);
         List<int> ilist = new List<int>();
         ilist.Add(1);
         ilist.Add(5);
         Tuple<List<int>, string> iInt = new Tuple<List<int>, string>(ilist, "helloWorld");
         moveUnitActions["addPrint"](iInt);
     }

If you want to see a parameters as they are then you should create a custom Class/Interface (depending on the case) instead of adding functions to Dictionary.

If you need a returnable value from function then use:

  Func<object, object>

instead of:

  Action<object>
Comment
Add comment · Show 8 · 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 Pharaoh_ · Apr 09, 2015 at 01:21 PM 0
Share

Hi, thanks for the reply. The problem is, I have multiple functions like RemoveUnit(). Each of them has a different set of parameters and their number ranges from 1 up to N. What I was hoping to get was that, when the match is found, simply invoke the method by passing the parameters right away.

avatar image DoTA_KAMIKADzE · Apr 09, 2015 at 02:28 PM 0
Share

Updated the answer - check the P.S. section of my answer.

avatar image Pharaoh_ · Apr 09, 2015 at 02:37 PM 0
Share

I have seen your edited version and thank you for that. I have no idea whatsoever what the point of Tuple is (not judging, I literally have no idea) and the "pass" keyword on the right of the "=" operator. It looks like you have made a generic object parameter so that I can include other types of variables as well. What if I have a method like Fade (GameObject whichUnit, float howLong, string whichAnimationWhileFading, AudioClip whichClipToPlay)? This is not a real method, but I want to show you that except for the plain RemoveUnit() which takes only a game object, there are also other methods with variability in number of parameters and types. Assu$$anonymous$$g that the "types" is resolved by using "object" and then using typecasting, what about the number of parameters?

avatar image DoTA_KAMIKADzE · Apr 09, 2015 at 03:04 PM 0
Share

Pass is just the name of the parameter (look at the function parameters).

I used Tuple to pass multiple different values as a single object and then get them back.

You can use unlimited numbers of params in that way, though for example Tuple that I used is not implemented in Unity's library so that you'll need to implement it yourself in the way you like it with functionality you want it to have, alternatively you can use:

 List<object>

or whatever else. For your method example above^ with my example in Answer you'll need to do something like that:

             //Encapsulate it like that:
             Tuple<GameObject,float,string,AudioClip> thisTuple = new Tuple<GameObject,float,string,AudioClip>(Add your variables here);
             moveUnitActions["SomeFunction"](thisTuple);
 
             //Then get the values back like that:
             public void SomeFunction(object pass)
             {
                 Tuple<GameObject, float, string, AudioClip> thisTuple = (Tuple<GameObject, float, string, AudioClip>)pass;
                 //thisTuple.Item1 -> gets the GameObject
                 //thisTuple.Item2 -> gets the float
                 //and so on
             }

avatar image DoTA_KAMIKADzE · Apr 09, 2015 at 07:39 PM 1
Share

If you don't want to use list you can do it like that for example:

 Action<object[]>

That will be a bit closer to Tuple I guess. An array of objects.

P.S. And if you'll do so then don't forget to correct my code by changing:

 //this 
 object whichUnit
 object pass
 //on this:
 object[] whichUnit
 object[] pass

Though as for me a custom class with all functions in it and as you said "a switch" is a better idea if it will do what you expect.

Show more comments
avatar image
0

Answer by blastproofgames · Apr 09, 2015 at 02:14 PM

Func and Action are delegates, thus function pointers. You can embed a function's property into a variable. Action returns void and Func returns the last parameter of the Func thus

     Func<int, bool>

takes an int and returns a bool.

I think you need something as simple as this

 Dictionary<string, Action> moveUnitActions = new Dictionary <string, Action> ();

 void RemoveUnit(GameObject whichUnit)
 {
     moveUnitActions["objectName"] = () => Destroy(whichUnit);
 }






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 Pharaoh_ · Apr 09, 2015 at 02:21 PM 0
Share

If you see my IEnumerator, you will realize there is a string parameter called collisionEvent. This deter$$anonymous$$es the action to be taken. Thus, if I use $$anonymous$$oveUnitTowardsUnit (....., "destroy"), it will search in the dictionary "moveUnitActions". When it finds the string "destroy", it will invoke the corresponding method. This is primarily why I am using the dictionary, different strings, such as "destroy", "fade", "kill", etc. will point to a different method. However, as I previously mentioned, each method has a different set of parameters, which is the confusing part for the lambda expression syntax. Your way, to my understanding, first calls the method RemoveUnit and then it implements the pointer (the Action). The goal is for the script to find which method has to be called, based on the string parameter I am passing (collisionEvent).

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

20 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

Related Questions

Coroutine Changed local variable behaviour in lambda, some confused 0 Answers

How to assign a function to UnityEvent without the use of lambdas? 1 Answer

Convert GameObject list to Transform list 1 Answer

Create DoTween from for loop? 1 Answer

New UI Button Dynamic onClick Listener problem 1 Answer


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