Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Dynamic LINQ return

Discussion in 'Scripting' started by qcw27710, Dec 7, 2019.

  1. qcw27710

    qcw27710

    Joined:
    Jul 9, 2019
    Posts:
    139
    I have a Dictionary in which Value is a class, that class contains about 15 variables.

    I was wondering whether it was possible to create a class that would return entries that match optional parameters of that class, in this fashion:
    Code (CSharp):
    1. class GetPlayer {
    2.     public string name;
    3.     public float health;
    4.     public int level;
    5. }
    6.  
    7. public void GetPlayer(string name = "", float? health = "", int? level = "") {
    8.     // return SomeLINQHere.WhereVariableMatchIfVariableIsNotNull;
    9. }
    And return entries that have their value equal to the parameter, if param is not null.
    If param is null, ignore the parameter.
    I do know structure of the class beforehand.
    I would do it manually, but I have a problem, what if I'm looking for an entry's variable that has a null value and I pass a null parameter?
    Is there a way to get this to work?

    Edit: I would like to have all items that match the requirements, not the first encounter only.
     
    Last edited: Dec 7, 2019
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,835
    You can write LINQ something like
    Code (CSharp):
    1. from var p in AllPlayers
    2. where (name == null || name.Value == p.name)
    3.     && (health == null || health.Value == p.health)
    4.     && (level == null || level.Value == p.level)
    5. select ...
    However, if you need to support both "I don't care about this parameter" and "I specifically want this parameter to have a value of null", then you'll need to work out a way of encoding the former other than simply setting the search value to null.
     
    qcw27710 likes this.
  3. qcw27710

    qcw27710

    Joined:
    Jul 9, 2019
    Posts:
    139
    Are there any obscene values I can set in parameter declaration as a default value that would (almost) never be used?
    Then I could treat it as if it's null and tell LINQ to ignore this variable if it has that crazy value.
    Special characters? Anything?

    Also you wrote
    select ...
    , what do I write behind it?

    Hmmm:
    Cannot convert initializer type "System.Collections.Generic.IEnumerable<Player>" to target type "System.Collections.Generic.List<Player>"


    in:
    Code (CSharp):
    1.  
    2.             List<Player> foundPlayers =
    3.                 from Player testPlayer in AllPlayers
    4.                 where (name == null || name.Value == testPlayer.name)
    5.                       && (health == null || health.Value == testPlayer.health)
    6.                       && (level == null || level.Value == testPlayer.level)
    7.                 select testPlayer;
    8.  
    9.             return foundPlayers;
     
    Last edited: Dec 7, 2019
  4. qcw27710

    qcw27710

    Joined:
    Jul 9, 2019
    Posts:
    139
    Found it.

    Apparently
    foundPlayers
    needs to be a var (because I'm a lazy programmer who won't type out the entirety), and the return result needs to be made
    ToList();
    . Apparently LINQ doesn't return List it returns IEnumerator.
     
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,835
    After "select" you put whatever you want it to return. If you want to return the entire player, then you've got it right. But hypothetically, if you only wanted the name of the player and not the whole player object, you could write something like "select testPlayer.name"

    The return value of an entire linq query will always be IEnumerable<something>, where "something" is the type of whatever you wrote in the "select" clause. If you need a List, you can write .ToList(); but that forces extra memory allocation, so generally only do that if it matters.

    Whether there are any values that will "almost never be used" depends entirely on your data set.

    If you can't figure out anything that's safe to use, then you can instead write separate functions with different argument lists.