1

I'm playing with the System.Linq in unity and I wonder if this is possible to achieve:

I would like to search a list of RaycastHits and if it contains a hit with a specific component on it I would like to return it instead of the RaycasHit

hits.FirstOrDefault(hit => hit.transform.GetComponent<Target>());

This returns me a RaycastHit which contains the component Target. I would like to instead get that Target component immediately so I don't have to get component again in a new line

RaycastHit target = hits.FirstOrDefault(hit => hit.transform.GetComponent<Target>());

Target combatTarget = target.transform.GetComponent<Target>();

Is it possible to cast it or map it in one line ??

4
  • 1
    It looks like you're packing enough punch into that functionality that it deserves its own function for best reuse -- it would then not only be 1 line to call, but a simple line at that. You could additionally try make it T generic, so that it allows more than just <Target> passing. Commented Mar 11, 2020 at 22:01
  • hit.transform.GetComponent<Target>() it gives target,and not a condition, why you use it inside a FirstOrDefault. for me use just Target combatTarget = hits.FirstOrDefault()?.transform?.GetComponent<Target>(); Commented Mar 11, 2020 at 22:08
  • 1
    @Sajid this would always only try the GetComponent on the first entry in hits ... which is not what you want ... Commented Mar 12, 2020 at 6:53
  • @derHugo ok I'm glad I'm not the only one who didn't know what they were talking about :) Commented Mar 12, 2020 at 15:25

1 Answer 1

5

Map it first, then get the first or default:

Target = hits
        .Select(hit => hit.transform.GetComponent<Target>())
        .FirstOrDefault(item => item != null);
Sign up to request clarification or add additional context in comments.

13 Comments

how about switching FirstOrDefault and Select, will give the same result and will call the GetComponent once.
@Sajid Changing the order would break it! Because then you would always try to get the first hit which is not null (which is always true since it is a struct and therefore would throw a compiler error) and then on this first hit result you would try to find GetComponent which might succeed or not! The order absolutely matters! You have to first get all hits that actually have the according component. Only then you want to get the first of them or null if not any was found!
However to be efficient here: This is actually a good example why not to use Linq too often ^^ Here you would anyway have to parse once with GetComponent through all hits. It would be way better to use e.g. foreach(var hit in hits){ var target = hit.transform.GetComponent<Target>(); if(target) { return target; } } return null; it's not a "one-liner" (everything can be in c# as you can see here ^^) but it's the most efficient you will get ;)
@LeoBartkus Still the order is important in Linq .. not for the execution order maybe but for what you are running which query on! hits.FirstOrDefault(hit => hit != null).Select(hit => hit.transform.GetComponent<Target>()); does: From the hits get the first element that is not null. On this first RayCastHit now run hit.transform.GetComponent<Target>() which might succeed or fail. This is totally not what you want. You want hits.Select(hit => hit.transform.GetComponent<Target>()).FirstOrDefault(); which returns e.g. null, target1, null, null, target2 and then takes the first valid
@derhugo correct, also FirstOrDefault() doesn't return another enumerable so changing the order won't even get past the compiler
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.