- Home /
Return value inexplicably becomes null
The following function gives me null whenever I call it.
private Avatar
GetAvatar()
{
List<Avatar> party = GameObject.FindObjectOfType<Party> ().GetAvatarsInParty ();
foreach (Avatar avatar in party)
{
if (avatar.name.Contains ("AvatarName"))
{
print(avatar);
return avatar;
}
}
return null;
}
It's definitely hitting return avatar, and print(avatar) is successfully printing the name of the FieldAvatar I want.
The only explanation is that I'm an idiot and that I don't understand something basic about how this is meant to work.
$$anonymous$$ake use of built-in debugger in $$anonymous$$ono or Visual Studio. It should help :)
Have you tried doing "return avatar as Avatar;", I know it seems stupid but it might be worth a shot. Also, what's the code that is calling this method look like? This would be pretty helpful.
@ThePunisher: Sorry, but this is pointless -.-
The avatar variable is of type Avatar. So whatever may be stored in that variable has to be an Avatar, has to be derived from Avatar or has to be null. The "as"-cast is also quite dangerous when used in this way. It is often the main cause for unexpected null-reference exceptions since the as-cast will return null if the cast is not possible. Such a cast will (with 100% certainty) do nothing but cause confusion.
The main point in having a strongly typed language is that you almost never have to care about types. Any mistake will be caught either by the compiler, or by a runtime exception. Note: A cast, no matter which kind, will never solve runtime problems. Along this line it should be mentioned that there's a difference between a "cast" and a "conversion". For example "casting" a float to an int is not a cast, but a type conversion. Type conversions can solve runtime problems as you effectively change the types involved. However an actual cast never changes the type of the object, only the type of the reference / variable. So casts never solve problems but are able to create them.
I disagree. I've used "as" plenty of times in places where it makes sense to use, specifically because it doesn't throw exceptions. I do prefer it over c-style casts, too. I also don't see how it is confusing. It's a pretty straight forward operator.
Now with regards to it being pointless in this scenario. Yeah, you are 100% correct. It is pointless. The line that initializes the party list would never compile if it wasn't returning a list of Avatar objects. I don't really know why I suggested it in the first place.
Edit: Perfect example of the proper usage. As with anything program$$anonymous$$g related, if used properly for what it was intended, then you won't run into any issues. Not sure why you have such a bad sentiment for this keyword.
public class ForBunny
{
private List<GameObject> m_masterList;
public List<T> FindObjectsOfType<T>() where T : class
{
List<T> result = new List<T>();
foreach (GameObject g in m_masterList)
{
// Perfect example of the usage of "as", we don't want to throw an exception here as it's expected that not all objects are of type T.
T temp = g as T;
if (temp != null)
{
result.Add(temp);
}
}
return result;
}
}
Answer by Bunny83 · May 09, 2017 at 08:12 PM
There are generally two cases i can imagine when seeing that portion of code:
Either that "Avatar" object that you return is derived from MonoBehaviour (or ScriptableObject) and got destroyed or wrongly initialized.
You might call that method several times and the one that matters returned null because the list might have been empty at that point.
Both cases can only be verified by you as the necessary information is missing in your question.
If this answer doesn't solve your problem, make sure you add more details to your question. Things of interest would be:
What is that Avatar you are returning? Most likely a class. Is it derived from something?
Where / when is the list (that is returned by "GetAvatarsInParty" ) inside your "Party" class initialized?
Try adding another Debug.Log / print after your for loop to see when no avatar was found.
Thanks for the information. I have a feeling it's to do with the first case as printouts confirm that the line return null is never reached.
Avatar is indeed derived from $$anonymous$$onoBehaviour. GetAvatarsInParty() just returns a list that's initialised earlier in the Party class.
And where are those Avatar instances attached to? You know that $$anonymous$$onoBehaviour derived classes are components which can not exist on their own. They always need to be attached to a GameObject. You can not create them with "new". Components can only be created with AddComponent (which basically happens when you drag a $$anonymous$$onoBehaviour class onto a gameobject in the inspector).
In $$anonymous$$ono / .NET it's actually impossible to actively "destroy" an object. However Unity has the Destroy method which see$$anonymous$$gly can be used to "destroy" any object that is derived from UnityEngine.Object. That's because any object that is derived from UnityEngine.Object has a native code counter part inside the actual engine. Unity is mainly written in C++. When you Destroy an object you actually destroy the native object. However the managed "proxy" object is still there because in managed memory the only one who can reclaim memory is the garbage collector.
So what happens to those managed object? Well, they will exist as long as there is a reference to them, just like any other managed class. However those object which have lost their native counter part will "pretend" to be null as the instance is basically useless in this state. If you need more information about those fake-null-objects, read this blog post.
Btw: The same thing happens when you create a $$anonymous$$onoBehaviour with "new". The operation doesn't fail. The managed object is actually created. But since it's missing it's native counterpart it simply pretends to be null.
You say that the line with the null return is never reached but how do you actually know that it never reaches it. I don't see any print statements outside of the if statement. Unless you verified this after posting and just didn't update the script you should add a print statement outside of the for loop (right before the null return) and run it again.