Home:ALL Converter>Why is the explicit cast necessary here

Why is the explicit cast necessary here

Ask Time:2019-07-09T13:56:46         Author:TvdH

Json Formatter

I am using a factory similar to this:

interface I<T>
{
    void Print();
}

class A : I<A>
{
    public string Id { get; }
    public A(string id) { Id = id; }
    public void Print() { Console.WriteLine(Id); }
}

class B : I<B>
{
    public int Id { get; }
    public B(int id) { Id = id; }
    public void Print() { Console.WriteLine(Id); }
}

class Factory
{
    public T Create<T>()
        where T : I<T>
    {
        if (typeof(T) == typeof(A))
            return (T)(I<T>)new A("A");
        else if (typeof(T) == typeof(B))
            return (T)(I<T>)new B(2);
        else
            throw new Exception("Unknown className");
    }
}

var sut = new Factory();
sut.Create<A>().Print();
sut.Create<B>().Print();

What I do not fully understand is: why is this double cast

(T)(I<T>)new A()

necessary? The compiler knows that

new A("A") is I<A>

and actually knows that

new A("A") is T

BTW: I am using the generic interface, since otherwise

Create<I>()

would compile fine but is not desired here.

Author:TvdH,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/56946123/why-is-the-explicit-cast-necessary-here
felix-b :

Your code reasons that when typeof(T) == typeof(A) is true, it guarantees that the type of expression new A(...) is compatible with T.\n\nThough this reasoning is correct at runtime, C# compiler doesn't treat typeof(T) == typeof(A) as any kind of \"type guard\".\n\n\n The compiler knows that new A(\"A\") isI<A>\n\n\nAgree\n\n\n and actually knows that new A(\"A\") is T\n\n\nNope, it cannot. In template-based approach (e.g. in C++) the \"generic\" function is compiled per every T encountered in source code, and then the compiler knows. However in .NET the generics is runtime-based, so that C# compiler must compile a code that would work for any T complying with the constraints, but besides that the concrete T is not known at compile time.\n\nIf you want to employ compiler \"type guards\" and avoid explicit casts, you can rewrite your code using C# pattern matching:\n\npublic T Create<T>()\n where T : I<T>\n{\n if (typeof(T) == typeof(A) && new A(\"A\") is T retA)\n return retA;\n else if (typeof(T) == typeof(B) && new B(2) is T retB)\n return retB;\n else\n throw new Exception(\"Unknown className\");\n} \n",
2019-07-09T06:26:08
trollingchar :

\n and actually knows that\n \n new A(\"A\") is T\n\n\nNo. If it knows that A is I<A>, does not mean that A and T is the same. T may be B and your cast will fail. Look at this code:\n\npublic T Create<T>()\n where T : I<T>\n{\n if (typeof(T) == typeof(A))\n return (T)(I<T>)new B(2);\n else if (typeof(T) == typeof(B))\n return (T)(I<T>)new A(\"A\");\n else\n throw new Exception(\"Unknown className\");\n}\n\n\nI swapped A and B and you cast B to A. The cast is invalid.",
2019-07-09T06:33:41
DotNet Developer :

\n What I do not fully understand is: why is this double cast\n necessary? The compiler knows that\n\n\nWhat compiler knows is following\n\nA is I<A>\nB is I<B>\nT is I<T>\nT is not A\nT is not I<A>\nT is not B\nT is not I<B>\n\n\nThat's why an instance of T must be cast to parent interface first then down to specific type.",
2019-07-09T06:55:07
yy