I've got a problem with inheritance and generics.
This is the code that illustrates my problem:
namespace TestApplication
{
public class MyClass<T>
{
private T field;
public MyClass(T field)
{
this.field = field;
}
}
public class MyIntClass : MyClass<int>
{
public MyIntClass(int field)
: base(field)
{
}
}
}
And when I try to do something like this:
MyClass<int> sth = new MyClass<int>(10);
MyIntClass intsth = (MyIntClass) sth;
I receive cast exception: Invalid cast exception. Unable to cast 'TestApplication.MyClass`1[System.Int32]' to 'TestApplication.MyIntClass'.
What is more I cannot create cast operator:
public static implicit operator MyIntClass(MyClass<int> myClass)
because: 'TestApplication.MyIntClass.implicit operator TestApplication.MyIntClass(TestApplication.MyClass)': user-defined conversions to or from a base class are not allowed
I need to create casts as described above. I don't know why I cannot cast from a type that is the base class. How can I solve this problem?
Thanks in advance.
Edit
Thanks for Your answers.
Now I see that i cannot convert from a base class to derived class and i see that it doesn't have anything to do with generics.
But why i cannot create user-defined conversions from a base class? I have a method that returns the base class. I am able to define a conversion method but creating a cast operator imho would be a better solution.
You can only cast from a base class to a derived class if the object is actually of type derived class. I mean, you can't cast an instance of base (MyClass<int>) to MyIntClass. You can, however cast it if it was actually of type MyIntClass stored as an MyClass<int> instance.
MyClass<int> foo = new MyIntClass();
MyIntClass bar = (MyIntClass)foo; // this works.
Assume:
class Base {
int x;
}
class Derived : Base {
int y;
}
Base foo = new Base();
Derived bar = (Derived)foo;
if it was allowed, what would the value of bar.y be?
In fact, converting from Derived to Base is not a conversion at all. It's just telling the compiler to let the variable of type Base to point to an object of type Derived. It is possible since derived has more or equal features than Base which is not the case in the other way around.
If you were able to create a conversion operator between base and derived classes, the C# compiler would be unable to distinguish it from the built in relationships defined for them. This is why you cannot create cast operators along inheritance hierarchies.
The other answers so far are correct, but I'd like to point out that your example has nothing to do with generics. It's the equivalent of:
using System;
class Base {}
class Child : Base {}
class Test
{
static void Main()
{
Base b = new Base();
// This will throw an exception
Child c = (Child) b;
}
}
In the comments you asked:
But why conversion from a base class is not allowed?
Simple - it would make no sense. Consider the example:
class BaseClass
{
public int x;
public BaseClass(int StartX)
{
this.x = StartX;
}
}
class ChildClass: BaseClass
{
public int Y;
public BaseClass(int StartX, StartY): base(StartX)
{
this.y = StartY;
}
}
class Program
{
public static void Main()
{
BaseClass B = new BaseClass(3);
ChildClass C = (ChildClass)B;
Console.WriteLine(C.y);
}
}
What do you suppose this program would output, assuming the cast worked? Even worse - imagine that BaseClass has two child classes - ChildClassA and ChildClassB. Do you want this to work?
ChildClassA A = new ChildClassA();
BaseClass bc = (BaseClass)A;
ChildClassB B = (ChildClassB)bc;
This would effectively allow to cast ChildClassA instances to ChildClassB - completely wrong.
As Mehrdad stated, you cannot downcast an object. Upcasting is implicit, therefore you cannot overwrite it.
As for the implicit operator, you can still create a constructor in the derived class which receives a parameter of type baseclass.
If you need to cast freely, define the variable as baseclass, but instantiate derived classes.
As has been said, you're trying to cast an object into a type that it doesn't derive from. Did you perhaps want to do this:
MyClass<int> sth = new MyIntClass(10);
MyIntClass intsth = (MyIntClass) sth;
Instead of creating an MyIntClass, try an alias:
using MyClass<int> = What.Ever.Namespace.MyIntClass;
This is now valid:
MyClass<int> foo = new MyClass<int>();
MyIntClass bar = (MyIntClass)foo;
Just understand that when doing the using alias, you have to qualify your namespace on the alias type name (What.Ever.Namespace).
Regarding your second question:
But why i cannot create user-defined conversions from a base class?
Well, suppose you have this scenario
class Base {
}
class Derived {
public static operator Derived(Base b) { ... }
}
and you tried to do this
Base x = new Derived();
Derived y = (Derived)x;
should the conversion be called? Of course not! The value inside x is actually of type Derived, so the cast is direct, without conversion. But if the value was not of type Derived, but a concrete Base, then the user-defined conversion has to happen because otherwise we'd have a compiler error. This all makes no sense; user-defined conversions are found in compile-time, and the type of the value of x is only known in runtime. Therefore, the compiler would not know what to do - call the user-defined conversion or simply cast the value...
Hope this makes a bit of sense to you.
Answering to your last edit.
This code does already compile, it only fails at runtime:
MyIntClass intsth = (MyIntClass) sth;
So, the following cast operator would be redundant if left explicit:
public static implicit operator MyIntClass(MyClass myClass)
So, the compiler should prevent you from adding that conversion. I think the error might be confusing, but I think it just forbids converting class B to class A if B is derived from A (the warning seemed to me to prevent any conversion to A, at first).
If the operator is made implicit, it is also dangerous, because a downcasting can always fail, so you have to:
show the compiler that you know that, by adding an explicit cast;
show the reader (which includes yourself, minutes later) that the operation might fail.
Assignment/conversion of a base class to a derived class makes sense if you consider assignment or conversion to be a value by value copy. What's confusing about c# for
newbies is the inconsistent way it does things:
'int' is a 'simple' type:
int i = 5; // <- this creates an int.
int j = i; // <- this creates another int and copies the value of i into j.
'Object' is not a simple type:
Object a; // <- this does not create a copy of 'Object', only a reference to one
Object b = new Object(); // <- this actually creates an Object
a = b; // <- this sets the reference to an object a to the reference to an object b.
// both of them reference the same Object. No values were copied.
If it were doing a copy of values then copying to base class to a derived class would
work. C# doesn't work like other languages.
I think that might be what's confusing you.
Related
ok i read a bit on this topic on stackoverflow, watched this & this, but still a bit confused about co/contra-variance.
from here
Covariance allows a "bigger" (less
specific) type to be substituted in an
API where the original type is only
used in an "output" position (e.g. as
a return value). Contravariance allows
a "smaller" (more specific) type to be
substituted in an API where the
original type is only used in an
"input" position.
i know it has to do with type safety.
about the in/out thing. can i say i use in when i need to write to it, and out when its read only. and in means contra-variance, out co-variance. but from the explanation above...
and here
For example, a List<Banana> can't be
treated as a List<Fruit> because
list.Add(new Apple()) is valid for
List but not for List<Banana>.
so shouldn't it be, if i were to use in/ am going to write to the object, it must be bigger more generic.
i know this question has been asked but still very confused.
I had to think long and hard on how to explain this well. Explaining is seems to be just as hard as understanding it.
Imagine you have a base class Fruit. And you have two subclasses Apple and Banana.
Fruit
/ \
Banana Apple
You create two objects:
Apple a = new Apple();
Banana b = new Banana();
For both of these objects you can typecast them into the Fruit object.
Fruit f = (Fruit)a;
Fruit g = (Fruit)b;
You can treat derived classes as if they were their base class.
However you cannot treat a base class like it was a derived class
a = (Apple)f; //This is incorrect
Lets apply this to the List example.
Suppose you created two Lists:
List<Fruit> fruitList = new List<Fruit>();
List<Banana> bananaList = new List<Banana>();
You can do something like this...
fruitList.Add(new Apple());
and
fruitList.Add(new Banana());
because it is essentially typecasting them as you add them into the list. You can think of it like this...
fruitList.Add((Fruit)new Apple());
fruitList.Add((Fruit)new Banana());
However, applying the same logic to the reverse case raises some red flags.
bananaList.Add(new Fruit());
is the same as
bannanaList.Add((Banana)new Fruit());
Because you cannot treat a base class like a derived class this produces errors.
Just in case your question was why this causes errors I'll explain that too.
Here's the Fruit class
public class Fruit
{
public Fruit()
{
a = 0;
}
public int A { get { return a; } set { a = value } }
private int a;
}
and here's the Banana class
public class Banana: Fruit
{
public Banana(): Fruit() // This calls the Fruit constructor
{
// By calling ^^^ Fruit() the inherited variable a is also = 0;
b = 0;
}
public int B { get { return b; } set { b = value; } }
private int b;
}
So imagine that you again created two objects
Fruit f = new Fruit();
Banana ba = new Banana();
remember that Banana has two variables "a" and "b", while Fruit only has one, "a".
So when you do this...
f = (Fruit)b;
f.A = 5;
You create a complete Fruit object.
But if you were to do this...
ba = (Banana)f;
ba.A = 5;
ba.B = 3; //Error!!!: Was "b" ever initialized? Does it exist?
The problem is that you don't create a complete Banana class.Not all the data members are declared / initialized.
Now that I'm back from the shower and got my self a snack heres where it gets a little complicated.
In hindsight I should have dropped the metaphor when getting into the complicated stuff
lets make two new classes:
public class Base
public class Derived : Base
They can do whatever you like
Now lets define two functions
public Base DoSomething(int variable)
{
return (Base)DoSomethingElse(variable);
}
public Derived DoSomethingElse(int variable)
{
// Do stuff
}
This is kind of like how "out" works you should always be able to use a derived class as if it were a base class, lets apply this to an interface
interface MyInterface<T>
{
T MyFunction(int variable);
}
The key difference between out/in is when the Generic is used as a return type or a method parameter, this the the former case.
lets define a class that implements this interface:
public class Thing<T>: MyInterface<T> { }
then we create two objects:
MyInterface<Base> base = new Thing<Base>;
MyInterface<Derived> derived = new Thing<Derived>;
If you were do this:
base = derived;
You would get an error like "cannot implicitly convert from..."
You have two choices, 1) explicitly convert them or, 2) tell the complier to implicitly convert them.
base = (MyInterface<Base>)derived; // #1
or
interface MyInterface<out T> // #2
{
T MyFunction(int variable);
}
The second case comes in to play if your interface looks like this:
interface MyInterface<T>
{
int MyFunction(T variable); // T is now a parameter
}
relating it to the two functions again
public int DoSomething(Base variable)
{
// Do stuff
}
public int DoSomethingElse(Derived variable)
{
return DoSomething((Base)variable);
}
hopefully you see how the situation has reversed but is essentially the same type of conversion.
Using the same classes again
public class Base
public class Derived : Base
public class Thing<T>: MyInterface<T> { }
and the same objects
MyInterface<Base> base = new Thing<Base>;
MyInterface<Derived> derived = new Thing<Derived>;
if you try to set them equal
base = derived;
your complier will yell at you again, you have the same options as before
base = (MyInterface<Base>)derived;
or
interface MyInterface<in T> //changed
{
int MyFunction(T variable); // T is still a parameter
}
Basically use out when the generic is only going to be used as a return type of the interface methods. Use in when it is going to be used as a Method parameter. The same rules apply when using delegates too.
There are strange exceptions but I'm not going to worry about them here.
Sorry for any careless mistakes in advance =)
Both covariance and contravariance in C# 4.0 refer to the ability of using a derived class instead of base class. The in/out keywords are compiler hints to indicate whether or not the type parameters will be used for input and output.
Covariance
Covariance in C# 4.0 is aided by out keyword and it means that a generic type using a derived class of the out type parameter is OK. Hence
IEnumerable<Fruit> fruit = new List<Apple>();
Since Apple is a Fruit, List<Apple> can be safely used as IEnumerable<Fruit>
Contravariance
Contravariance is the in keyword and it denotes input types, usually in delegates. The principle is the same, it means that the delegate can accept more derived class.
public delegate void Func<in T>(T param);
This means that if we have a Func<Fruit>, it can be converted to Func<Apple>.
Func<Fruit> fruitFunc = (fruit)=>{};
Func<Apple> appleFunc = fruitFunc;
Why are they called co/contravariance if they are basically the same thing?
Because even though the principle is the same, safe casting from derived to base, when used on the input types, we can safely cast a less derived type (Func<Fruit>) to a more derived type (Func<Apple>), which makes sense, since any function that takes Fruit, can also take Apple.
Let me share my take on this topic.
Disclaimer: ignore null assignments, I'm using them to keep the code relatively short and they are just enough to see what compiler wants to tell us.
Let's start with a hierarchy of classes:
class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
Now define some interfaces, to illustrate what in and out generic modifiers actually do:
interface IInvariant<T>
{
T Get(); // ok, an invariant type can be both put into and returned
void Set(T t); // ok, an invariant type can be both put into and returned
}
interface IContravariant<in T>
{
//T Get(); // compilation error, cannot return a contravariant type
void Set(T t); // ok, a contravariant type can only be **put into** our class (hence "in")
}
interface ICovariant<out T>
{
T Get(); // ok, a covariant type can only be **returned** from our class (hence "out")
//void Set(T t); // compilation error, cannot put a covariant type into our class
}
Ok, so why bother using interfaces with in and out modifiers if they restrict us? Let's see:
Invariance
Lets start with invariance (no in, no out modifiers)
Invariance experiment
Consider IInvariant<Mammal>
IInvariant<Mammal>.Get() - returns a Mammal
IInvariant<Mammal>.Set(Mammal) - accepts a Mammal
What if we try: IInvariant<Mammal> invariantMammal = (IInvariant<Animal>)null?
Whoever calls IInvariant<Mammal>.Get() expects a Mammal, but IInvariant<Animal>.Get() - returns an Animal. Not every Animal is a Mammal so it's incompatible.
Whoever calls IInvariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IInvariant<Animal>.Set(Animal) accepts any Animal (including Mammal), it's compatible
CONCLUSION: such assignment is incompatible
And what if we try: IInvariant<Mammal> invariantMammal = (IInvariant<Dog>)null?
Whoever calls IInvariant<Mammal>.Get() expects a Mammal, IInvariant<Dog>.Get() - returns a Dog, every Dog is a Mammal, so it's compatible.
Whoever calls IInvariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IInvariant<Dog>.Set(Dog) accepts only Dogs (and not every Mammal as a Dog), it's incompatible.
CONCLUSION: such assignment is incompatible
Let's check if we're right
IInvariant<Animal> invariantAnimal1 = (IInvariant<Animal>)null; // ok
IInvariant<Animal> invariantAnimal2 = (IInvariant<Mammal>)null; // compilation error
IInvariant<Animal> invariantAnimal3 = (IInvariant<Dog>)null; // compilation error
IInvariant<Mammal> invariantMammal1 = (IInvariant<Animal>)null; // compilation error
IInvariant<Mammal> invariantMammal2 = (IInvariant<Mammal>)null; // ok
IInvariant<Mammal> invariantMammal3 = (IInvariant<Dog>)null; // compilation error
IInvariant<Dog> invariantDog1 = (IInvariant<Animal>)null; // compilation error
IInvariant<Dog> invariantDog2 = (IInvariant<Mammal>)null; // compilation error
IInvariant<Dog> invariantDog3 = (IInvariant<Dog>)null; // ok
THIS ONE IS IMPORTANT: It's worth noticing that depending on whether the generic type parameter is higher or lower in class hierarchy, the generic types themselves are incompatible for different reasons.
Ok, so let's find out how could we exploit it.
Covariance (out)
You have covariance when you use out generic modifier (see above)
If our type looks like: ICovariant<Mammal>, it declares 2 things:
Some of my methods return a Mammal (hence out generic modifier) - this is boring
None of my methods accept a Mammal - this is interesting though, because this is the actual restriction imposed by the out generic modifier
How can we benefit from out modifier restrictions? Look back at the results of the "Invariance experiment" above. Now try to see what happens when make the same experiment for covariance?
Covariance experiment
What if we try: ICovariant<Mammal> covariantMammal = (ICovariant<Animal>)null?
Whoever calls ICovariant<Mammal>.Get() expects a Mammal, but ICovariant<Animal>.Get() - returns an Animal. Not every Animal is a Mammal so it's incompatible.
ICovariant.Set(Mammal) - this is no longer an issue thanks to the out modifier restrictions!
CONCLUSION such assignment is incompatible
And what if we try: ICovariant<Mammal> covariantMammal = (ICovariant<Dog>)null?
Whoever calls ICovariant<Mammal>.Get() expects a Mammal, ICovariant<Dog>.Get() - returns a Dog, every Dog is a Mammal, so it's compatible.
ICovariant.Set(Mammal) - this is no longer an issue thanks to the out modifier restrictions!
CONCLUSION such assignment is COMPATIBLE
Let's confirm it with the code:
ICovariant<Animal> covariantAnimal1 = (ICovariant<Animal>)null; // ok
ICovariant<Animal> covariantAnimal2 = (ICovariant<Mammal>)null; // ok!!!
ICovariant<Animal> covariantAnimal3 = (ICovariant<Dog>)null; // ok!!!
ICovariant<Mammal> covariantMammal1 = (ICovariant<Animal>)null; // compilation error
ICovariant<Mammal> covariantMammal2 = (ICovariant<Mammal>)null; // ok
ICovariant<Mammal> covariantMammal3 = (ICovariant<Dog>)null; // ok!!!
ICovariant<Dog> covariantDog1 = (ICovariant<Animal>)null; // compilation error
ICovariant<Dog> covariantDog2 = (ICovariant<Mammal>)null; // compilation error
ICovariant<Dog> covariantDog3 = (ICovariant<Dog>)null; // ok
Contravariance (in)
You have contravariance when you use in generic modifier (see above)
If our type looks like: IContravariant<Mammal>, it declares 2 things:
Some of my methods accept a Mammal (hence in generic modifier) - this is boring
None of my methods return a Mammal - this is interesting though, because this is the actual restriction imposed by the in generic modifier
Contravariance experiment
What if we try: IContravariant<Mammal> contravariantMammal = (IContravariant<Animal>)null?
IContravariant<Mammal>.Get() - this is no longer an issue thanks to the in modifier restrictions!
Whoever calls IContravariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IContravariant<Animal>.Set(Animal) accepts any Animal (including Mammal), it's compatible
CONCLUSION: such assignment is COMPATIBLE
And what if we try: IContravariant<Mammal> contravariantMammal = (IContravariant<Dog>)null?
IContravariant<Mammal>.Get() - this is no longer an issue thanks to the in modifier restrictions!
Whoever calls IContravariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IContravariant<Dog>.Set(Dog) accepts only Dogs (and not every Mammal as a Dog), it's incompatible.
CONCLUSION: such assignment is incompatible
Let's confirm it with the code:
IContravariant<Animal> contravariantAnimal1 = (IContravariant<Animal>)null; // ok
IContravariant<Animal> contravariantAnimal2 = (IContravariant<Mammal>)null; // compilation error
IContravariant<Animal> contravariantAnimal3 = (IContravariant<Dog>)null; // compilation error
IContravariant<Mammal> contravariantMammal1 = (IContravariant<Animal>)null; // ok!!!
IContravariant<Mammal> contravariantMammal2 = (IContravariant<Mammal>)null; // ok
IContravariant<Mammal> contravariantMammal3 = (IContravariant<Dog>)null; // compilation error
IContravariant<Dog> contravariantDog1 = (IContravariant<Animal>)null; // ok!!!
IContravariant<Dog> contravariantDog2 = (IContravariant<Mammal>)null; // ok!!!
IContravariant<Dog> contravariantDog3 = (IContravariant<Dog>)null; // ok
BTW, this feels a bit counterintuitive, doesn't it?
// obvious
Animal animal = (Dog)null; // ok
Dog dog = (Animal)null; // compilation error, not every Animal is a Dog
// but this looks like the other way around
IContravariant<Animal> contravariantAnimal = (IContravariant<Dog>) null; // compilation error
IContravariant<Dog> contravariantDog = (IContravariant<Animal>) null; // ok
Why not both?
So can we use both in and out generic modifiers? - obviously not.
Why? Look back at what restrictions do in and out modifiers impose. If we wanted to make our generic type parameter both covariant and contravariant, we would basically say:
None of the methods of our interface returns T
None of the methods of our interface accepts T
Which would essentially make our generic interface non-generic.
How to remember it?
You can use my tricks :)
"covariant" is shorter than "contravaraint" and this opposite to the lengths of their modifiers ("out" and "in" respectively)
contravaraint is a little counterintuitive (see the example above)
Covariance is pretty easy to understand. It's natural. Contravariance is more confusing.
Take a close look at this example from MSDN. See how SortedList expects an IComparer, but they are passing in a ShapeAreaComparer : IComparer. The Shape is the "bigger" type (it's in the signature of the callee, not the caller), but contravariance allows the "smaller" type - the Circle - to be substituted for everywhere in the ShapeAreaComparer that would normally take a Shape.
Hope that helps.
Before coming to topic, lets have a quick refresher:
Base class reference can hold a derived class object BUT not vice-versa.
Covariance:
Covariance lets you to pass a derived type object where a base type object is expected
Covariance can be applied on delegate, generic, array, interface, etc.
Contravariance:
Contravariance is applied to parameters. It allows a method with the parameter of a base class to be assigned to a delegate that expects the parameter of a derived class
Have a look at simple example below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CovarianceContravarianceDemo
{
//base class
class A
{
}
//derived class
class B : A
{
}
class Program
{
static A Method1(A a)
{
Console.WriteLine("Method1");
return new A();
}
static A Method2(B b)
{
Console.WriteLine("Method2");
return new A();
}
static B Method3(B b)
{
Console.WriteLine("Method3");
return new B();
}
public delegate A MyDelegate(B b);
static void Main(string[] args)
{
MyDelegate myDel = null;
myDel = Method2;// normal assignment as per parameter and return type
//Covariance, delegate expects a return type of base class
//but we can still assign Method3 that returns derived type and
//Thus, covariance allows you to assign a method to the delegate that has a less derived return type.
myDel = Method3;
A a = myDel(new B());//this will return a more derived type object which can be assigned to base class reference
//Contravariane is applied to parameters.
//Contravariance allows a method with the parameter of a base class to be assigned to a delegate that expects the parameter of a derived class.
myDel = Method1;
myDel(new B()); //Contravariance,
}
}
}
In Jons words:
Covariance allows a "bigger" (less specific) type to be substituted in an API where the original type is only used in an "output" position (e.g. as a return value). Contravariance allows a "smaller" (more specific) type to be substituted in an API where the original type is only used in an "input" position.
I found his explanation confusing at first - but it made sense to me once to be substitued is emphasised, combined with the example from the C# programming guide:
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;
The converter delegate helps me to understand it:
delegate TOutput Converter<in TInput, out TOutput>(TInput input);
TOutput represents covariance where a method returns a more specific type.
TInput represents contravariance where a method is passed a less specific type.
public class Dog { public string Name { get; set; } }
public class Poodle : Dog { public void DoBackflip(){ System.Console.WriteLine("2nd smartest breed - woof!"); } }
public static Poodle ConvertDogToPoodle(Dog dog)
{
return new Poodle() { Name = dog.Name };
}
List<Dog> dogs = new List<Dog>() { new Dog { Name = "Truffles" }, new Dog { Name = "Fuzzball" } };
List<Poodle> poodles = dogs.ConvertAll(new Converter<Dog, Poodle>(ConvertDogToPoodle));
poodles[0].DoBackflip();
Let’s start with the class hierarchy we are using in the covariance and contravariance examples:
public class Weapon { }
public class Sword : Weapon { }
public class TwoHandedSword : Sword { }
Covariance means you can return (output) the instance of a subtype as its supertype. Here is an
example:
[Fact]
public void Covariance_tests()
Assert.IsType<Sword>(Covariance());
Assert.Throws<InvalidCastException>(() => BreakCovariance());
}
// We can return a Sword into a Weapon
private Weapon Covariance()
=> new Sword();
// We cannot return a Sword into a TwoHandedSword
private TwoHandedSword BreakCovariance()
=> (TwoHandedSword)new Sword();
As shown in the preceding example, one way to break covariance is to return a supertype as a subtype.
On the other hand, contravariance means you can input the instance of a subtype as its supertype.
It is basically the same thing but for inputs, like this:
[Fact]
public void Contravariance_tests()
{
// We can pass a Sword as a Weapon
Contravariance(new Sword());
// We cannot pass a Weapon as a Sword
BreakContravariance(new Weapon()); // Compilation error
}
private void Contravariance(Weapon weapon) { }
private void BreakContravariance(Sword weapon) { }
The same polymorphic rule applies, as we can see from the preceding code. We can use a subtype as
a supertype.
ok i read a bit on this topic on stackoverflow, watched this & this, but still a bit confused about co/contra-variance.
from here
Covariance allows a "bigger" (less
specific) type to be substituted in an
API where the original type is only
used in an "output" position (e.g. as
a return value). Contravariance allows
a "smaller" (more specific) type to be
substituted in an API where the
original type is only used in an
"input" position.
i know it has to do with type safety.
about the in/out thing. can i say i use in when i need to write to it, and out when its read only. and in means contra-variance, out co-variance. but from the explanation above...
and here
For example, a List<Banana> can't be
treated as a List<Fruit> because
list.Add(new Apple()) is valid for
List but not for List<Banana>.
so shouldn't it be, if i were to use in/ am going to write to the object, it must be bigger more generic.
i know this question has been asked but still very confused.
I had to think long and hard on how to explain this well. Explaining is seems to be just as hard as understanding it.
Imagine you have a base class Fruit. And you have two subclasses Apple and Banana.
Fruit
/ \
Banana Apple
You create two objects:
Apple a = new Apple();
Banana b = new Banana();
For both of these objects you can typecast them into the Fruit object.
Fruit f = (Fruit)a;
Fruit g = (Fruit)b;
You can treat derived classes as if they were their base class.
However you cannot treat a base class like it was a derived class
a = (Apple)f; //This is incorrect
Lets apply this to the List example.
Suppose you created two Lists:
List<Fruit> fruitList = new List<Fruit>();
List<Banana> bananaList = new List<Banana>();
You can do something like this...
fruitList.Add(new Apple());
and
fruitList.Add(new Banana());
because it is essentially typecasting them as you add them into the list. You can think of it like this...
fruitList.Add((Fruit)new Apple());
fruitList.Add((Fruit)new Banana());
However, applying the same logic to the reverse case raises some red flags.
bananaList.Add(new Fruit());
is the same as
bannanaList.Add((Banana)new Fruit());
Because you cannot treat a base class like a derived class this produces errors.
Just in case your question was why this causes errors I'll explain that too.
Here's the Fruit class
public class Fruit
{
public Fruit()
{
a = 0;
}
public int A { get { return a; } set { a = value } }
private int a;
}
and here's the Banana class
public class Banana: Fruit
{
public Banana(): Fruit() // This calls the Fruit constructor
{
// By calling ^^^ Fruit() the inherited variable a is also = 0;
b = 0;
}
public int B { get { return b; } set { b = value; } }
private int b;
}
So imagine that you again created two objects
Fruit f = new Fruit();
Banana ba = new Banana();
remember that Banana has two variables "a" and "b", while Fruit only has one, "a".
So when you do this...
f = (Fruit)b;
f.A = 5;
You create a complete Fruit object.
But if you were to do this...
ba = (Banana)f;
ba.A = 5;
ba.B = 3; //Error!!!: Was "b" ever initialized? Does it exist?
The problem is that you don't create a complete Banana class.Not all the data members are declared / initialized.
Now that I'm back from the shower and got my self a snack heres where it gets a little complicated.
In hindsight I should have dropped the metaphor when getting into the complicated stuff
lets make two new classes:
public class Base
public class Derived : Base
They can do whatever you like
Now lets define two functions
public Base DoSomething(int variable)
{
return (Base)DoSomethingElse(variable);
}
public Derived DoSomethingElse(int variable)
{
// Do stuff
}
This is kind of like how "out" works you should always be able to use a derived class as if it were a base class, lets apply this to an interface
interface MyInterface<T>
{
T MyFunction(int variable);
}
The key difference between out/in is when the Generic is used as a return type or a method parameter, this the the former case.
lets define a class that implements this interface:
public class Thing<T>: MyInterface<T> { }
then we create two objects:
MyInterface<Base> base = new Thing<Base>;
MyInterface<Derived> derived = new Thing<Derived>;
If you were do this:
base = derived;
You would get an error like "cannot implicitly convert from..."
You have two choices, 1) explicitly convert them or, 2) tell the complier to implicitly convert them.
base = (MyInterface<Base>)derived; // #1
or
interface MyInterface<out T> // #2
{
T MyFunction(int variable);
}
The second case comes in to play if your interface looks like this:
interface MyInterface<T>
{
int MyFunction(T variable); // T is now a parameter
}
relating it to the two functions again
public int DoSomething(Base variable)
{
// Do stuff
}
public int DoSomethingElse(Derived variable)
{
return DoSomething((Base)variable);
}
hopefully you see how the situation has reversed but is essentially the same type of conversion.
Using the same classes again
public class Base
public class Derived : Base
public class Thing<T>: MyInterface<T> { }
and the same objects
MyInterface<Base> base = new Thing<Base>;
MyInterface<Derived> derived = new Thing<Derived>;
if you try to set them equal
base = derived;
your complier will yell at you again, you have the same options as before
base = (MyInterface<Base>)derived;
or
interface MyInterface<in T> //changed
{
int MyFunction(T variable); // T is still a parameter
}
Basically use out when the generic is only going to be used as a return type of the interface methods. Use in when it is going to be used as a Method parameter. The same rules apply when using delegates too.
There are strange exceptions but I'm not going to worry about them here.
Sorry for any careless mistakes in advance =)
Both covariance and contravariance in C# 4.0 refer to the ability of using a derived class instead of base class. The in/out keywords are compiler hints to indicate whether or not the type parameters will be used for input and output.
Covariance
Covariance in C# 4.0 is aided by out keyword and it means that a generic type using a derived class of the out type parameter is OK. Hence
IEnumerable<Fruit> fruit = new List<Apple>();
Since Apple is a Fruit, List<Apple> can be safely used as IEnumerable<Fruit>
Contravariance
Contravariance is the in keyword and it denotes input types, usually in delegates. The principle is the same, it means that the delegate can accept more derived class.
public delegate void Func<in T>(T param);
This means that if we have a Func<Fruit>, it can be converted to Func<Apple>.
Func<Fruit> fruitFunc = (fruit)=>{};
Func<Apple> appleFunc = fruitFunc;
Why are they called co/contravariance if they are basically the same thing?
Because even though the principle is the same, safe casting from derived to base, when used on the input types, we can safely cast a less derived type (Func<Fruit>) to a more derived type (Func<Apple>), which makes sense, since any function that takes Fruit, can also take Apple.
Let me share my take on this topic.
Disclaimer: ignore null assignments, I'm using them to keep the code relatively short and they are just enough to see what compiler wants to tell us.
Let's start with a hierarchy of classes:
class Animal { }
class Mammal : Animal { }
class Dog : Mammal { }
Now define some interfaces, to illustrate what in and out generic modifiers actually do:
interface IInvariant<T>
{
T Get(); // ok, an invariant type can be both put into and returned
void Set(T t); // ok, an invariant type can be both put into and returned
}
interface IContravariant<in T>
{
//T Get(); // compilation error, cannot return a contravariant type
void Set(T t); // ok, a contravariant type can only be **put into** our class (hence "in")
}
interface ICovariant<out T>
{
T Get(); // ok, a covariant type can only be **returned** from our class (hence "out")
//void Set(T t); // compilation error, cannot put a covariant type into our class
}
Ok, so why bother using interfaces with in and out modifiers if they restrict us? Let's see:
Invariance
Lets start with invariance (no in, no out modifiers)
Invariance experiment
Consider IInvariant<Mammal>
IInvariant<Mammal>.Get() - returns a Mammal
IInvariant<Mammal>.Set(Mammal) - accepts a Mammal
What if we try: IInvariant<Mammal> invariantMammal = (IInvariant<Animal>)null?
Whoever calls IInvariant<Mammal>.Get() expects a Mammal, but IInvariant<Animal>.Get() - returns an Animal. Not every Animal is a Mammal so it's incompatible.
Whoever calls IInvariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IInvariant<Animal>.Set(Animal) accepts any Animal (including Mammal), it's compatible
CONCLUSION: such assignment is incompatible
And what if we try: IInvariant<Mammal> invariantMammal = (IInvariant<Dog>)null?
Whoever calls IInvariant<Mammal>.Get() expects a Mammal, IInvariant<Dog>.Get() - returns a Dog, every Dog is a Mammal, so it's compatible.
Whoever calls IInvariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IInvariant<Dog>.Set(Dog) accepts only Dogs (and not every Mammal as a Dog), it's incompatible.
CONCLUSION: such assignment is incompatible
Let's check if we're right
IInvariant<Animal> invariantAnimal1 = (IInvariant<Animal>)null; // ok
IInvariant<Animal> invariantAnimal2 = (IInvariant<Mammal>)null; // compilation error
IInvariant<Animal> invariantAnimal3 = (IInvariant<Dog>)null; // compilation error
IInvariant<Mammal> invariantMammal1 = (IInvariant<Animal>)null; // compilation error
IInvariant<Mammal> invariantMammal2 = (IInvariant<Mammal>)null; // ok
IInvariant<Mammal> invariantMammal3 = (IInvariant<Dog>)null; // compilation error
IInvariant<Dog> invariantDog1 = (IInvariant<Animal>)null; // compilation error
IInvariant<Dog> invariantDog2 = (IInvariant<Mammal>)null; // compilation error
IInvariant<Dog> invariantDog3 = (IInvariant<Dog>)null; // ok
THIS ONE IS IMPORTANT: It's worth noticing that depending on whether the generic type parameter is higher or lower in class hierarchy, the generic types themselves are incompatible for different reasons.
Ok, so let's find out how could we exploit it.
Covariance (out)
You have covariance when you use out generic modifier (see above)
If our type looks like: ICovariant<Mammal>, it declares 2 things:
Some of my methods return a Mammal (hence out generic modifier) - this is boring
None of my methods accept a Mammal - this is interesting though, because this is the actual restriction imposed by the out generic modifier
How can we benefit from out modifier restrictions? Look back at the results of the "Invariance experiment" above. Now try to see what happens when make the same experiment for covariance?
Covariance experiment
What if we try: ICovariant<Mammal> covariantMammal = (ICovariant<Animal>)null?
Whoever calls ICovariant<Mammal>.Get() expects a Mammal, but ICovariant<Animal>.Get() - returns an Animal. Not every Animal is a Mammal so it's incompatible.
ICovariant.Set(Mammal) - this is no longer an issue thanks to the out modifier restrictions!
CONCLUSION such assignment is incompatible
And what if we try: ICovariant<Mammal> covariantMammal = (ICovariant<Dog>)null?
Whoever calls ICovariant<Mammal>.Get() expects a Mammal, ICovariant<Dog>.Get() - returns a Dog, every Dog is a Mammal, so it's compatible.
ICovariant.Set(Mammal) - this is no longer an issue thanks to the out modifier restrictions!
CONCLUSION such assignment is COMPATIBLE
Let's confirm it with the code:
ICovariant<Animal> covariantAnimal1 = (ICovariant<Animal>)null; // ok
ICovariant<Animal> covariantAnimal2 = (ICovariant<Mammal>)null; // ok!!!
ICovariant<Animal> covariantAnimal3 = (ICovariant<Dog>)null; // ok!!!
ICovariant<Mammal> covariantMammal1 = (ICovariant<Animal>)null; // compilation error
ICovariant<Mammal> covariantMammal2 = (ICovariant<Mammal>)null; // ok
ICovariant<Mammal> covariantMammal3 = (ICovariant<Dog>)null; // ok!!!
ICovariant<Dog> covariantDog1 = (ICovariant<Animal>)null; // compilation error
ICovariant<Dog> covariantDog2 = (ICovariant<Mammal>)null; // compilation error
ICovariant<Dog> covariantDog3 = (ICovariant<Dog>)null; // ok
Contravariance (in)
You have contravariance when you use in generic modifier (see above)
If our type looks like: IContravariant<Mammal>, it declares 2 things:
Some of my methods accept a Mammal (hence in generic modifier) - this is boring
None of my methods return a Mammal - this is interesting though, because this is the actual restriction imposed by the in generic modifier
Contravariance experiment
What if we try: IContravariant<Mammal> contravariantMammal = (IContravariant<Animal>)null?
IContravariant<Mammal>.Get() - this is no longer an issue thanks to the in modifier restrictions!
Whoever calls IContravariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IContravariant<Animal>.Set(Animal) accepts any Animal (including Mammal), it's compatible
CONCLUSION: such assignment is COMPATIBLE
And what if we try: IContravariant<Mammal> contravariantMammal = (IContravariant<Dog>)null?
IContravariant<Mammal>.Get() - this is no longer an issue thanks to the in modifier restrictions!
Whoever calls IContravariant<Mammal>.Set(Mammal) expects that a Mammal can be passed. Since IContravariant<Dog>.Set(Dog) accepts only Dogs (and not every Mammal as a Dog), it's incompatible.
CONCLUSION: such assignment is incompatible
Let's confirm it with the code:
IContravariant<Animal> contravariantAnimal1 = (IContravariant<Animal>)null; // ok
IContravariant<Animal> contravariantAnimal2 = (IContravariant<Mammal>)null; // compilation error
IContravariant<Animal> contravariantAnimal3 = (IContravariant<Dog>)null; // compilation error
IContravariant<Mammal> contravariantMammal1 = (IContravariant<Animal>)null; // ok!!!
IContravariant<Mammal> contravariantMammal2 = (IContravariant<Mammal>)null; // ok
IContravariant<Mammal> contravariantMammal3 = (IContravariant<Dog>)null; // compilation error
IContravariant<Dog> contravariantDog1 = (IContravariant<Animal>)null; // ok!!!
IContravariant<Dog> contravariantDog2 = (IContravariant<Mammal>)null; // ok!!!
IContravariant<Dog> contravariantDog3 = (IContravariant<Dog>)null; // ok
BTW, this feels a bit counterintuitive, doesn't it?
// obvious
Animal animal = (Dog)null; // ok
Dog dog = (Animal)null; // compilation error, not every Animal is a Dog
// but this looks like the other way around
IContravariant<Animal> contravariantAnimal = (IContravariant<Dog>) null; // compilation error
IContravariant<Dog> contravariantDog = (IContravariant<Animal>) null; // ok
Why not both?
So can we use both in and out generic modifiers? - obviously not.
Why? Look back at what restrictions do in and out modifiers impose. If we wanted to make our generic type parameter both covariant and contravariant, we would basically say:
None of the methods of our interface returns T
None of the methods of our interface accepts T
Which would essentially make our generic interface non-generic.
How to remember it?
You can use my tricks :)
"covariant" is shorter than "contravaraint" and this opposite to the lengths of their modifiers ("out" and "in" respectively)
contravaraint is a little counterintuitive (see the example above)
Covariance is pretty easy to understand. It's natural. Contravariance is more confusing.
Take a close look at this example from MSDN. See how SortedList expects an IComparer, but they are passing in a ShapeAreaComparer : IComparer. The Shape is the "bigger" type (it's in the signature of the callee, not the caller), but contravariance allows the "smaller" type - the Circle - to be substituted for everywhere in the ShapeAreaComparer that would normally take a Shape.
Hope that helps.
Before coming to topic, lets have a quick refresher:
Base class reference can hold a derived class object BUT not vice-versa.
Covariance:
Covariance lets you to pass a derived type object where a base type object is expected
Covariance can be applied on delegate, generic, array, interface, etc.
Contravariance:
Contravariance is applied to parameters. It allows a method with the parameter of a base class to be assigned to a delegate that expects the parameter of a derived class
Have a look at simple example below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CovarianceContravarianceDemo
{
//base class
class A
{
}
//derived class
class B : A
{
}
class Program
{
static A Method1(A a)
{
Console.WriteLine("Method1");
return new A();
}
static A Method2(B b)
{
Console.WriteLine("Method2");
return new A();
}
static B Method3(B b)
{
Console.WriteLine("Method3");
return new B();
}
public delegate A MyDelegate(B b);
static void Main(string[] args)
{
MyDelegate myDel = null;
myDel = Method2;// normal assignment as per parameter and return type
//Covariance, delegate expects a return type of base class
//but we can still assign Method3 that returns derived type and
//Thus, covariance allows you to assign a method to the delegate that has a less derived return type.
myDel = Method3;
A a = myDel(new B());//this will return a more derived type object which can be assigned to base class reference
//Contravariane is applied to parameters.
//Contravariance allows a method with the parameter of a base class to be assigned to a delegate that expects the parameter of a derived class.
myDel = Method1;
myDel(new B()); //Contravariance,
}
}
}
In Jons words:
Covariance allows a "bigger" (less specific) type to be substituted in an API where the original type is only used in an "output" position (e.g. as a return value). Contravariance allows a "smaller" (more specific) type to be substituted in an API where the original type is only used in an "input" position.
I found his explanation confusing at first - but it made sense to me once to be substitued is emphasised, combined with the example from the C# programming guide:
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;
The converter delegate helps me to understand it:
delegate TOutput Converter<in TInput, out TOutput>(TInput input);
TOutput represents covariance where a method returns a more specific type.
TInput represents contravariance where a method is passed a less specific type.
public class Dog { public string Name { get; set; } }
public class Poodle : Dog { public void DoBackflip(){ System.Console.WriteLine("2nd smartest breed - woof!"); } }
public static Poodle ConvertDogToPoodle(Dog dog)
{
return new Poodle() { Name = dog.Name };
}
List<Dog> dogs = new List<Dog>() { new Dog { Name = "Truffles" }, new Dog { Name = "Fuzzball" } };
List<Poodle> poodles = dogs.ConvertAll(new Converter<Dog, Poodle>(ConvertDogToPoodle));
poodles[0].DoBackflip();
Let’s start with the class hierarchy we are using in the covariance and contravariance examples:
public class Weapon { }
public class Sword : Weapon { }
public class TwoHandedSword : Sword { }
Covariance means you can return (output) the instance of a subtype as its supertype. Here is an
example:
[Fact]
public void Covariance_tests()
Assert.IsType<Sword>(Covariance());
Assert.Throws<InvalidCastException>(() => BreakCovariance());
}
// We can return a Sword into a Weapon
private Weapon Covariance()
=> new Sword();
// We cannot return a Sword into a TwoHandedSword
private TwoHandedSword BreakCovariance()
=> (TwoHandedSword)new Sword();
As shown in the preceding example, one way to break covariance is to return a supertype as a subtype.
On the other hand, contravariance means you can input the instance of a subtype as its supertype.
It is basically the same thing but for inputs, like this:
[Fact]
public void Contravariance_tests()
{
// We can pass a Sword as a Weapon
Contravariance(new Sword());
// We cannot pass a Weapon as a Sword
BreakContravariance(new Weapon()); // Compilation error
}
private void Contravariance(Weapon weapon) { }
private void BreakContravariance(Sword weapon) { }
The same polymorphic rule applies, as we can see from the preceding code. We can use a subtype as
a supertype.
I have a base class :
interface IBaseClass{
int x;
int y;
baseClass someMethod();
}
and some derived class :
class dClass1 : IBaseClass {
int x;
int y;
baseClass someMethod();
}
class dClass2 : IBaseClass {
int x;
int y;
baseClass someMethod();
}
The value of property according to the subclass algorithm is different from other subclass
now i want cast these subclass to them:
dClass1 c1=new dClass1 ();
c1.x=4;
c1.y=5;
dClass2 c2=c1;//cast to dClass2 , but value of property set by according to the own algorithm
Console.WriteLine("{0}, {1}", c1.x, c1.y);//4,5
Console.WriteLine("{0}, {1}", c2.x, c2.y);//7,1
First off, lets make it clear that IBaseClass is not a base class, its an interface, which is something quite different. Pointing out the differences is not in the scope of this answer but you can easily read about it, starting here.
That said, as others have stated, you can't do what you want directly. Consider the canonical example IAnimal, Dog, Cat, etc. Evey dog and every cat are animals, but cats are not dogs and dogs are not cats and you are basically asking a cat to be a dog; you first need to teach cats how to dogify (they won't do that out of the box for you).
In order to achieve this behavior there are quite a few ways how you can do it:
User defined cast: You can define operators that convert from one class to another. If you make them implicit you'd even get your code to compile as it is right now:
public static implicit operator dClass2(dClass1 obj)
{ //logic to convert obj to corresponding new dClass2 instance }
Now this would be legal:
var c1 = new dClass1();
dClass2 c2 = c1; // implicit cast operator is called.
Note that if you were to implement the cast operator as explicit, the former code would not compile. You would need to explicitly cast c1:
var c2 = (dClass2)c1;
Define a dClass2 constructor that takes a dClass1 argument:
public dClass2(dClass1 obj) { ... }
and you'd write the following code:
var c1 = new dClass1();
var c2 = new dClass2(c1);
Define a static factory method in dClass2 that takes a dClass1 argument and produces a new dClass2 instance:
public static dClass2 CreateFrom(dClass1 obj) { ... }
And the corresponding code:
var c1 = new dClass1();
var c2 = dClass2.CreateFrom(c1);
Many more I haven't bothered to think about...
Which one you choose is up to personal taste. I'd probably use the explicit cast, but there is nothing inherently wrong with any of the options available.
dClass1 and dClass2 are two different types. You can't directly cast one to the other. You'd have to convert one to the other. For example:
dClass1 c1 = new dClass1
{
x=4,
y=5
};
dClass2 c2 = new dClass2
{
x = c1.x,
y = c1.y
};
Or, using multiple lines like your original code:
dClass1 c1 = new dClass1();
c1.x=4;
c1.y=5;
dClass2 c2 = new dClass2();
c2.x = c1.x;
c2.y = c1.y;
The point is, the system has no way to directly cast one type to another type. You can encapsulate this conversion into factory methods on either type, or on separate classes. But casting isn't an option. Just because the two types have members of the same type/name/etc. doesn't make them the same type.
What you're trying to do isn't possible. You can cast an object to a less (or more in some cases) derived type, but you can't cast an object to another type unless you define a custom cast on the type.
You can read about defining custom casts here: https://msdn.microsoft.com/en-us/library/ms173105.aspx
How Force type cast between classes of different namespaces.
Both namespaces have same class.
You can't cast an object to a type it is not. If it belongs to a different namespace then it is not the same class. You will have to create a converter:
public static Namespace1.SomeClass Convert(Namespace2.SomeClass someClass) {
Namespace1.SomeClass rtn = new Namespace1.SomeClass();
rtn.SomeProp = someClass.SomeProp;
rtn.SomeOtherProp = someClass.SomeOtherProp;
return rtn;
}
you could even use reflection to set all the properties on Namespace1.SomeClass that have the same name as Namespace2.SomeClass.
Also, if you own the code to one of the classes, you can check into overloading explicit and implicit on your class.
You can create generic Converter so you don't have to do this each time you need to cast a different type of objects,
T ConvertObject<T>(object M) where T : class
{
// Serialize the original object to json
// Desarialize the json object to the new type
var obj = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(M));
return obj;
}
// Test ObjectToCast is type Namespace1.Class, obj is Namespace2
Namespace2.Class obj = ConvertObject<Namespace2.Class>(ObjectToCast);
Assuming that both classes are the same this will work.
You can't cast from a Type to a different Type, even if the code of the class is exactly the same.
You can create a Converter capable to convert between the two types, or provide implicit/explicit casts inside both classes implementations or eventually you can try Automapper.
You need to qualify the type:
namespace Foo
{
class Bar {}
}
namespace Baz
{
class Bar {}
}
Foo.Bar x = new Foo.Bar();
Baz.Bar y = (Baz.Bar)x;
Of course, this will fail unless there is a conversion defined.
This is not possible. A type include its namespace as part of its full name.
Its like the town of Springfield: same name but from different states. They are all different.
A possible approach would be to overload the cast operator of one of the type so that they can be cast into another type. It won't be a real cast, as the result will be to create a new object with the same value.
public static explicit operator Massachusetts.Springfield(Illinois.Springfield town)
{
return new Massachusetts.Springfield(town); // or any other code to copy the fields from one type to the other
}
If both classes are serializable, you can serialize the first object to XML, change the "namespace" in the xml and deserialize it again.
The fact that the two classes have the same name doesn't mean anything to the compiler. You may have Foo.Orange and Bar.Orange, but to the compiler it may as well be Apple and Orange. To convert:
namespace Foo
{
public class Orange{}
public static explicit operator Foo.Orange(Bar.Orange) { // conversion code }
}
namespace Bar
{
public class Orange{}
public static explicit operator Bar.Orange(Foo.Orange) { // conversion code }
}
// somewhere else
Foo.Orange o = new Foo.Orange();
Bar.Orange bar = (Bar.Orange)o; // and vice-versa
I have two interfaces IHeaderRow, and IDetailRow
I then have an object that implements both RawRow:IHeaderRow, IDetailRow
I then need to cast it to HeaderRow which implements IHeaderRow.
But when I try, it ends up being null or giving an exception.
I can cast ObjectRawRow to either interface IHeaderRow, or IDetailRow
var ObjectIHeaderRow = ObjectRawRow as IHeaderRow;
var ObjectIDetailRow = ObjectRawRow as IDetailRow;
But I can not cast ObjectRawRow to HeaderRow , or ObjectIHeaderRow to HeaderRow.
It throws the error Cannot convert source type 'IA' to target type 'A'
I need to cast it into the actual class HeaderRow.
Thoughts?
EDIT:
Even though setting up an explicit cast took care of the issue I thought I'd provide an answer to the people wondering, WHY I was doing what I was.
In short, I'm sequentially processing a file. Line by line. I read the row into RawRow, and until I look at a few values, I don't actually know what type of row it is going to be. I then wanted to cast it to the proper type.
You can only implicitly cast objects to types they inherit from or implement - since RawRow doesn't derive from HeaderRow, it's not possible.
Depending on your requirements, you could overcome this by writing an explicit conversion operator, creating a HeaderRow constructor that accepts a RawRow as its prototype, or by modifying your code to operate on an IHeaderRow.
Why do you need to cast it to a HeaderRow in the first place? If IHeaderRow produced the api that a HeaderRow implements, than you should just be able to act on IHeaderRow "objects" using the defined methods.
The point of an interface is so that you can treat a grouping of different objects as a similar type. Not so that you can cast different objects between classes that are not linked by inheritance.
First, why do you need to do such a weird cast? There's probably another design for what you're trying to do.
Second, the reason you can't do the cast is because a RawRow isn't an HeaderRow. The only guarantee it makes is that it implements IHeaderRow. The problem is that it has a bunch of other stuff too, stuff that HeaderRow doesn't have. And vice versa - HeaderRow probably has a bunch of stuff that ObjectRawRow doesn't have.
Imagine your classes look like this:
interface IHeaderRow
{
string GetText();
}
class HeaderRow : IHeaderRow
{
public string GetText()
{
return "My Label";
}
public int GetFoo()
{
return 42;
}
}
class ObjectRawRow : IHeaderRow
{
public string GetText()
{
return "My Raw Label";
}
}
Now if you do this, you're ok:
ObjectRawRow row = new ObjectRawRow();
IHeaderRow header = row as IHeaderRow;
string label = header.GetText(); // fine, since GetText is guaranteed to exist
But try this on for size:
ObjectRawRow row = new ObjectRawRow();
HeaderRow header = row as HeaderRow;
int magic = header.GetFoo(); // BOOM! Method doesn't exist,
// because the object isn't really a HeaderRow under the covers.
// It's still really an ObjectRawRow. What do you do now? Crash hard is what.
And that's why you can't cast outside of the inheritance tree.
You cannot cast ObjectRawRow to HeaderRow unless one inherits from the other.
Interfaces have nothing to do with it.
Consider:
class Shape
interface IHasCorners
class Rectangle : IHasCorners, Shape
class Triangle : IHasCorners, Shape
Rectangle myRectangle = new Rectangle();
Triangle myTriangle = new Triangle();
//upcasts
Shape s = (Shape)myRectangle;
IHasCorners hc = (IHasCorners)myRectangle;
//downcasts
Rectangle r2 = (Rectangle)s;
r2 = (Rectangle)hc;
//upcasts
s = (Shape)myTriangle;
hc = (IHasCorners) myTriangle;
//these downcasts won't work
//the variables now reference a Triangle instance
Rectangle r3 = (Rectangle)s;
r3 = (Rectangle)hc;
You will not be able to make this cast unless there is an inheritance relationship between the types. If that is not possible then the best you can do is create an explicit conversion operator that allows you to cast one type as another type.
If you do create an explicit conversion you should understand that this will be slower than casting as you will be invoking an method that will do work as opposed to casting which only changes the reference type and doesn't change any of the memory on the heap.
Consider this example that doesn't compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo { }
class Bar { }
Since there is no inheritance relations between the types nor is there an explicit conversion from Foo to Bar this cannot compile.
But adding an explicit conversion allows it to compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo
{
public static explicit operator Bar(Foo foo)
{
return new Bar();
}
}
class Bar { }
You can only cast an instance to a particular class if the object is actually an instance of that class (or is derived from that class).
It is not possible to cast an instance of class A to completely unrelated class B (which is what you're trying to do), even if they implement the same interfaces.
You can use the explicit keyword to create methods that will be called when you try to cast from IA to A. The reason it doesn't work without you writing your own method is because the compiler doesn't know what to do with the values that aren't being provided.