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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Why AddComponet<x>() as x

Discussion in 'Getting Started' started by aMIGA_dUDE, Apr 30, 2021.

  1. aMIGA_dUDE

    aMIGA_dUDE

    Joined:
    Oct 12, 2019
    Posts:
    21

    MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>() as MeshFilter;
    MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>() as MeshRenderer;
    MeshCollider meshCollider = gameObject.AddComponent<MeshCollider>() as MeshCollider;


    I just dont get why having the as in this as can not do AddComponent<MeshFilter>() as MeshCollider, it has to be AddComponent<MeshFilter>() as MeshFilter. So why is this repeating being done for? What is the point.
     
  2. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,137
    The "as" keyword is basically a form of casting.

    https://docs.microsoft.com/en-us/do...e/operators/type-testing-and-cast#as-operator

    Therefore when you type.
    Code (csharp):
    1. MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>() as MeshFilter;
    What you are effectively doing is.
    Code (csharp):
    1. MeshFilter meshFilter = (MeshFilter)gameObject.AddComponent<MeshFilter>();
    A line like the following doesn't work because a MeshFilter cannot hold a MeshCollider.
    Code (csharp):
    1. MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>() as MeshCollider;
    By the way none of these castings are required with the generic form of AddComponent even though the docs show it that way. The following is perfectly valid.
    Code (csharp):
    1. MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
     
  3. aMIGA_dUDE

    aMIGA_dUDE

    Joined:
    Oct 12, 2019
    Posts:
    21

    float testFloat = 3.13f;
    int testInt = (int)testFloat;
    Debug.Log($"testFloat: {testFloat} , testInt: {testInt}");

    This works with a debug output of testFloat: 3.13 , testInt: 3

    float testFloat = 3.13f;
    int testInt = testFloat as int;
    Debug.Log($"testFloat: {testFloat} , testInt: {testInt}");

    Dosn't work and error out with error CS0077: The as operator must be used with a reference type or nullable type ('int' is a non-nullable value type)
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,845
    That's because "as" does not convert an object (value); it merely tells the compiler to treat the value as something more specific. If I have a method that returns a Fruit, but I happen to know in this particular case that it should always return an Apple (a subclass of Fruit), then I can tell the compiler to give me the result as type Apple.

    That doesn't apply in the case of floats and ints; firstly because these are not objects, and secondly because a float is not an int. To treat a float as an int would be invalid. You need to use the form (int)testFloat, which actually converts the new value (i.e. generates a new value of the required type), rather than just treating the old value as something else.
     
    aMIGA_dUDE and Schneider21 like this.
  5. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,137
    Sorry, I should have been more specific with my explanation because while it is essentially a cast it is designed to be used in ways other than normal casting with the biggest use case being to optimize LINQ. Outside of that the actual use case of "as" is when you expect a cast to fail. This allows you to detect if the cast will fail.

    The following code uses the "as" keyword to verify that the object is the correct type and exit the function with a false if it is not.
    Code (csharp):
    1. public bool Equals(Object obj)
    2. {
    3.     SomeType other = obj as SomeType;
    4.     if (other == null) return false;
    5.     // do stuff
    6. }
    The following code uses the "is" keyword to do the same thing.
    Code (csharp):
    1. public bool Equals(Object obj)
    2. {
    3.     if (obj == null) return false;
    4.     if (!(obj is SomeType)) return false;
    5.     // do stuff
    6. }
    Notice that the second example has two comparisons. We have to check if the object is null prior to checking type with "is" but we can do both at the same time with one comparison with the "as" keyword.

    By comparison the following code will throw an exception if the type isn't correct. From there we would have to handle the exception before continuing execution while the "as" and "is" keywords save us from that giving us much cleaner code.
    Code (csharp):
    1. public bool Equals(Object obj)
    2. {
    3.     SomeType other = (SomeType)obj;
    4. }
    Additional reading and references.
    https://stackoverflow.com/questions/7566212/when-should-you-use-the-as-keyword-in-c-sharp
     
    Last edited: Apr 30, 2021
  6. aMIGA_dUDE

    aMIGA_dUDE

    Joined:
    Oct 12, 2019
    Posts:
    21
    I think got it. The last clue I need was from https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0039?f1url=?appId=roslyn&k=k(CS0039)

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Example : MonoBehaviour
    4. {
    5.  
    6.     /* Use this as my bases of what doing here
    7.      * https://forum.unity.com/threads/why-addcomponet-x-as-x.1101991/
    8.      * https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator
    9.      * https://stackoverflow.com/questions/7566212/when-should-you-use-the-as-keyword-in-c-sharp
    10.      * https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0039?f1url=%3FappId%3Droslyn%26k%3Dk(CS0039)
    11.      */
    12.     void Start()
    13.     {
    14.         Gun greenGun = new Gun();
    15.         Weapon blueWeapon = new Gun();
    16.         greenGun.name = "AB12";
    17.         greenGun.cost = 12;
    18.         greenGun.bullets = 23;
    19.         greenGun.range = 34;
    20.         Debug.Log($"greenGun-1 class: {greenGun} name: {greenGun.name} cost: {greenGun.cost} bullets: {greenGun.bullets} range: {greenGun.range}");
    21.         blueWeapon.name = "XZ89";
    22.         blueWeapon.cost = 56;
    23.         Debug.Log($"blueWeapon class: {blueWeapon} name: {blueWeapon.name} cost: {blueWeapon.cost}");
    24.         greenGun = blueWeapon as Gun;
    25.         Debug.Log($"greenGun-2 class: {greenGun} name: {greenGun.name} cost: {greenGun.cost} bullets: {greenGun.bullets} range: {greenGun.range}");
    26.     }
    27. }
    28.  
    29. class Weapon
    30. {
    31.     public string name;
    32.     public int cost;
    33. }
    34.  
    35. class Gun : Weapon
    36. {
    37.     public int bullets;
    38.     public float range;
    39. }
    Which output's
    greenGun-1 class: Gun name: AB12 cost: 12 bullets: 23 range: 34
    weapon class: Gun name: XZ89 cost: 56
    greenGun-2 class: Gun name: XZ89 cost: 56 bullets: 0 range: 0