This is a very uncommon problem and there are definetly many workarounds, but I would like to understand what is actually going on and why it's not working.
So I have 3 assemblies in a test solution, first assembly has type ClassA:
public class ClassA
{
public string Name { get; set; }
}
Second assembly references first assembly and has ClassB:
public class ClassB
{
public string Name { get; set; }
public static explicit operator ClassA(ClassB objB)
{
return new ClassA
{
Name = objB.Name
};
}
}
which has an explicit operator to cast to type ClassA. Let's say that we cannot use inheritance for some reason and just using casting as a convenient way of transforming one type to another.
Now, the last assembly references second assembly (and not the first one!) and has type ClassC:
public class ClassC
{
public string Name { get; set; }
public static explicit operator ClassB(ClassC objC)
{
return new ClassB
{
Name = objC.Name
};
}
}
which uses explicit cast operator for same reason as ClassB.
Now the interesting part: if I try to cast from ClassC to ClassB in my code, like this:
ClassC objC = new ClassC();
ClassB objB = (ClassB)objC;
I get the following error:
Error 1 The type 'FirstAssembly.ClassA' is defined in an assembly that is not referenced. You must add a reference to assembly 'FirstAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
I could easily create new instance of ClassB and just initialize it with values from ClassC instance (like I do inside explicit cast operator), and it would work fine. So what is wrong here?
In section, 6.4.5 User-defined explicit conversions of the C# Language Specification (version 4.0) it reads:
A user-defined explicit conversion from type S to type T is processed as follows:
• Determine the types S0 and T0. If S or T are nullable types, S0 and T0 are their underlying types, otherwise S0 and T0 are equal to S and T respectively.
• Find the set of types, D, from which user-defined conversion operators will be considered. This set consists of S0 (if S0 is a class or struct), the base classes of S0 (if S0 is a class), T0 (if T0 is a class or struct), and the base classes of T0 (if T0 is a class).
It doesn't define how the compiler will "Find the set of types" but I think it searches all relevant classes looking for candidates for the next step:
• Find the set of applicable user-defined and lifted conversion operators, U. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in D that convert from a type encompassing or encompassed by S to a type encompassing or encompassed by T. If U is empty, the conversion is undefined and a compile-time error occurs.
This causes it to attempt to resolve the reference to ClassA.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With