Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot convert from 'out T' to 'out Component'

Tags:

c#

here is some C# code that does not compile, giving the following message :

cannot convert from 'out T' to 'out Component'

    public void Get<T>(out T c) where T : Component
    {
        m_components.TryGetValue(typeof(T), out c);
    }

Here is code that does compile :

    public void Get<T>(out T c) where T : Component
    {
        Component temp;
        m_components.TryGetValue(typeof(T), out temp);
        c = (T)temp;
    }

I wonder why the first code is not valid since the "where T : Component" explicitly states that T is of type Component.

Thanks

like image 822
noon Avatar asked Dec 03 '09 06:12

noon


3 Answers

It's because out parameter types cannot be covariant/contravariant. The type of the variable must exactly match the parameter type.

See:

class Super { }
class Sub : Super { }

void Test(out Super s)
{
    s = new Super();
}

void Main()
{
    Sub mySub = new Sub();
    Test(out mySub); //doesn't work
}
like image 135
Rex M Avatar answered Nov 07 '22 20:11

Rex M


I'm going to take a shot at a more elaborate version of @Rex's answer and slightly corrected version of @Courtney's signature in that the type is Component, not object. Courtney's answer is basically right, just the types are a bit off.

bool TryGetValue(Type key, out Component result)
{
       if (this.Contains(key))
       {
           result = this[key]; // the type of result is Component!
           return true;
       }

      return false;
}

by passing T as the object type, you are trying to implicitly cast the base type Component to a subtype T. That is why your second example works. TryGetValue doesn't know about your Generic type T, it thinks everything in m_Components is a Component object.

This is a pretty common thing to get stuck thinking backwards. Because it's a parameter, not the return type, you get sucked into thinking it should work like any other parameter. However, because it's an out, it actually is better thought of as a return type for this purpose... it is going to try to assign the value of it's internal work to the parameter you provide.

like image 23
Jim L Avatar answered Nov 07 '22 20:11

Jim L


I think the problem is in the out and it does not relate to Generics

we can produce the same error as follows

class A
{
}

void fn(out object x)
{
 x= new object();
}
void main()
{
 A x;
fn(out x); //error
}
like image 20
Ahmed Avatar answered Nov 07 '22 21:11

Ahmed