Assuming I have a basic class hierarchy like this:
public abstract class BaseClass { }
public class X : BaseClass { }
public class Y: BaseClass { }
And I have a generic struct as this:
public struct MyStruct<T>
where T: BaseClass, new()
{
}
I can then create an instance as follows:
var x = new MyStruct<X>();
Now i want to provide an operation (a constructor, or a conversion operator) on MyStruct
, which allows me to convert MyStruct<X>
to MyStruct<Y>
:
MyStruct<Y> my = new MyStruct<X>();
When i write a constructor as follows:
public struct MyStruct<T>
where T: BaseClass, new()
{
public MyStruct(MyStruct<T2> value)
where T2: BaseClass, new()
{
...
}
}
The compiler does not understand what i'm trying to do (it seems it cannot distinguish between MyStruct<T>
and MyStruct<T2>
).
How do i convert MyStruct<X>
to MyStruct<Y>
from within MyStruct<T>
?
You can't do this in the constructor, but you should be able to write a conversion method in the struct, something like:
public struct MyStruct<T>
where T: BaseClass, new()
{
// Convert this instance of MyStruct<T> to a new MyStruct<TOut>
public MyStruct<TOut> ToMyStruct<TOut>()
{
...
}
}
Which would allow you to write:
struct2 = struct1.ToMyStruct<TOut>()
C# has no concept of generic conversion operators; any conversion operator, whether implicit or explicit, must either import or export a type which is fully defined by the generic parameters of the defining type. This means that Foo<T>
can define a conversion operators to or from Bar<T>
(and vice versa), and Foo<T,U>
can define conversions to or from Bar<U>
, but not vice versa. It also means that a Foo<T>
can define conversions to or from `Bar, but not vice versa. Unfortunately, there is no way to have a conversion operator which can import or export a type with generic type parameters beyond those of the defining type, even if the parameters would be constrained in such a way that the cast would succeed.
What all this means is that one must often use methods rather than operators to perform conversions (or, for that matter, to perform mixed-type operations). Generic type resolution for methods is pretty smart (at least if one is willing to include a default-null dummy parameter) but for operators it's pretty limited.
Incidentally, if the only purpose for which a struct uses a generic type parameter is to define public fields of that type, it should in theory be possible for such a struct to support covariance without regard for whether the structs are "mutable", since an assignment of a KeyValuePair<FordFocus,SiameseCat>
to a KeyValuePair<Vehicle,Animal>
would represent the assignment of a FordFocus
to a Vehicle
and a SiameseCat
to an Animal
, both of which are type-safe. This fails, however, because all boxed structures are always mutable, and mutable aspects of a type cannot safely support covariance.
I made it work using the following approach:
public static implicit operator MyStruct<T>(MyStruct<X> value)
{
return new MyStruct<T>(value);
}
public static implicit operator MyStruct<T>(MyStruct<Y> value)
{
return new MyStruct<T>(value);
}
....
This is limited to known types (X, Y, ...), but lets me write the following code:
MyStruct<X> x = new MyStruct<X>(...);
MyStruct<Y> y = x;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.