C# Casting types from Interfaces - c#

I want to create a set of classes that are very similar and can be cast to each other types. My idea was that I would create an Interface object and implement it through a base class. Then create additional classes that inherit from my base. I could then use the Interface to work with the common (base) methods and cast an object from the BASE object to a custom type.
interface ImyInterface {
}
public class MyBase : ImyInterface {
}
public class MyCustom1 : MyBase {
}
public class MyCustom2 : MyBase {
}
// in helper class
public static MyBase GetGeneralOjbect() {
// get a generic base object
return new MyBase();
}
// How I'm trying to use this
MyCustom1 obj = GetGeneralOjbect() as MyCustom1;
This seems to work except for the casting of the object statement. MyCustom1 is always null even though the static helper GetGeneralOjbect returns a good MyBase object. Maybe this can't be done or I'm not doing it correctly. Any input would be appreciated.

This is because you can cast a MyCustom1 or MyCustom2 to MyBase, but not necessarily the other way.
When you create a MyBase via MyBase b = new MyBase();, b is a MyBase but not a MyCustom2, so casting b to MyCustom2 will fail.
What you can do is:
MyBase b = new MyCustom2();
MyCustom2 c = b as MyCustom2();
What you can't do is:
MyBase b = new MyCustom2();
MyCustom1 c = b as MyCustom1();

The "as" keyword says "if this object which is statically typed as MyBase has a runtime type of MyCustom1, then give it back to me statically typed as MyCustom1; otherwise, give me a null reference". The object you are casting has a runtime type of MyBase, not MyCustom1, which is why you are getting a null reference.

Basically you can cast up an inheritance chain but not down it. Say you had the following class heirarchy:
public class A {
}
public class B : A {
}
public class C : B {
}
If you instantiated a new instance of type B you could cast it to A but not C.

Have you considered using Factory Pattern?

An instance of MyCustom1 can be used whenever an instance of MyBase is expected, but MyBase cannot be used when MyCustom1 is expected.

Related

The purpose of using generic methods where generic is some base class

Is there any purpose of using generic methods where T generic is base class? For example
class A: BaseClass
{
}
class B : BaseClass
{
}
class C
{
public T test<T> (T aa) where T : BaseClass
{
}
}
why do not just write in this way?
class C
{
public BaseClass test (BaseClass aa)
{
}
}
What gives us generic in this situation?
Your (non-generic) variant is returning an object of type BaseClass while the generic variant is returning an object of whatever T is (i.e. A or B or BaseClass).
Notice how your method returns an instance of T.
Using generics, this is valid:
A input = new A();
A output = c.test(input);
If we try and do the same with the version which just uses BaseClass:
A input = new A();
A output = c.test(input); // Error: can not assign instance of 'BaseClass' to 'A'
This is, obviously, because test returns an instance of BaseClass. Instead we have to write:
A input = new A();
A output = (A)c.test(input);
... and we don't have any compile-time guarantees that test actually returns an instance of A in this case, and not an instance of B.

"Recasting" a subclass instance (declared as base class) to an interface - why does it work?

I want to have subclasses that implement arbitrary interfaces, but are declared as a base class, so that the application would try to "recast" the instances to that interface and use them if recast is successful.
I had some doubts and so I made this short spike and, both for my joy and surprise, it works.
My question is: Why and how does it work? Is there a formal way that I could have known it would work beforehand? Some sort of "casting rules" in C#?
class Program
{
static void Main(string[] args)
{
var obj = new SubClass() as BaseClass;
Console.WriteLine(obj is ISubClass); // output = "True"
Console.ReadKey();
}
}
class BaseClass { }
class SubClass : BaseClass, ISubClass { }
interface ISubClass { }
You have created an instance of SubClass and SubClass is inheriting from both the interface and BaseClass, so we can cast the reference of the object SubClass to either of those. The actual type still remains SubClass, you have just casted the reference to it's base type, if you check by calling GetType() on the instance you will see that it will evaluate to type SubClass, so it is just reference conversion, the original object still is same.
You might want to read about polymorphsim and Reference Conversion
(edit by OP) From second link:
Conversions from a base type to a derived type only succeed at run time if the value being converted is a null reference or a reference type that is either the derived type itself or a more derived type.
(...) a class type can always be cast to an interface type that it implements. Similarly, conversions from an interface type to a class type that implements it only succeed at run time if the value being converted is a null reference or a reference type that is either the class type itself or a type derived from the class type.
The object is still of type SubClass you only use as reference the type of BaseClass. And because it is of type SubClass it also does implement the ISubClass interface. A cast does not update the origin object, it does only "change the reference" to the object.
Like you show in your code, with simple changes:
you create a SubClass object: SubClass obj = new SubClass();
now you cast it: BaseClass bObj = obj as BaseClass; but the original object is still of type SubClass. You could also do this ISubClass sObj = obj as ISubClass; and ISubClass sObj = bObj as ISubClass because you work always on the origin object.
Another example is polymorphism. The whole concept would not work, when the origin object would be changed when casting.
As general hint, you do not need the explicite cast to var obj = new SubClass() as BaseClass;, this would also work: BaseClass obj = new SubClass();
At compile time, you won't be able to call methods of SubClass (even if the methods are declared in ISublass), but at runtime, if you make that check, it will return true.
When you cast to the parent class you are limited to only using those methods and properties available to any object that inherits from the parent class. The object is still of the type you created with the new statement, SubClass.
class BaseClass
{
public int BaseProp { get; set; }
}
class SubClass : BaseClass, ISubClass
{
public int ChildProp { get; set; }
}
interface ISubClass
{
int ChildProp { get; set; }
}
class Program
{
public static void Main(string[] args)
{
var obj = new SubClass() as BaseClass;
// obj IS SubClass type, but we are only going to use properties and methods
// available to ANY BaseClass
obj.BaseProp = 1; // this is fine
obj.ChildProp = 2; // this doesn't work (BaseClass does not contain a definition for ChildProp)
(obj as SubClass).ChildProp = 2; // this works
}
}
When you use "as" keyword, it does not create a new instance of BaseClass. The instance still remains of SubClass.
If you have created a new instance of BaseClass from SubClass instance it would have displayed false as you expected.

Call generics with base class gives cannot convert from base class to T

I have the following setup and it seems that my object cannot be converted to the generic type. While it is actually the base class. Why doesn't this work? It seems so logical to me.
public class AList<T> where T : A
{
void DoStuff(T foo)
{
}
void CallDoStuff()
{
DoStuff(new A()); // ERROR: Cannot convert A to T
}
}
public class A
{
}
The problem here is that the constraint says that T must be A or a class derived from A.
Now, when you instantiate AList with a concrete type, T is a very specific class. And if you didn't instantiate AList with A itself but with a subclass of it, T is a subclass of A.
You can't convert an instance with a runtime type of the base class to one of its subclasses, as it misses all the information that is being added by the subclass.
Example:
public class Animal
{
public int Foo { get; set; }
}
public class Cat : Animal
{
public int Bar { get; set; }
}
Derived d = new Base();
Would you expect that code to work? Surely not, because a Cat is also a Animal but a Animal is not a Cat.
If you would expect the above code to actually work, ask yourself what is supposed to happen when the following code is executed: d.Bar = 42;
Animal doesn't contain a definition for Bar.
The same is happening in your code - it's just a little bit more obscured with the generics in the game.
T could be also a class that derives from A so you can't put instance of A as a parameter of type T. Something like invoking method, that takes int with and argument that is of type object.
This is the same reason that is an object can not be converted to int implicitly.
The method expects a child class and you are passing the parent, so you need an explicit cast.
Because you are asking T to extend A. So you can replace T with A but not A with T.
if Cat : Animal it doesn't mean you can always convert an Animal to a Cat.
Try and use Activator to give you an instance of A from T because you know that T has to be A due to your constraint, so there isn't a need to use new A() anywhere as you have T, so you can just create an instance of T.
T obj = Activator.CreateInstance<T>();
DoStuff(obj);
Or do a cast of your object as other answers have mentioned, however this will not work in all cases.
T obj = (T)new A();
DoStuff(obj);

Instantiate a class (or derived) with internal constructor

let's say I have a class defined in an assembly with:
public class BaseClass
{
internal BaseClass()
{
}
}
And in another assembly, I would like to instanciate this class with :
BaseClass c = new BaseClass();
I get the CS0143 error.
Trying another way, I try to create a derived class of the first one :
public class DerivedClass : BaseClass
{
}
but same error.
The BaseClass is not sealed. How can I instantiate this class or a derived one? Of course, I can't modify the BaseClass.
You'll have to use reflection to get the internal constructor and invoke it:
var ci = typeof(BaseClass).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
var instance = (BaseClass)ci.Invoke(new object[0]);
Since the existence of the constructor is only discovered at run-time, this approach will break if the constructor of BaseClass is changed or removed.
1) You want an actual instance of the base class:
There needs to be some method in the assembly that it's in that constructs it for you. This would normally be called a "factory". It might look like this:
public class BaseFactory
{
public static BaseClass Create() { return new BaseClass(); } //may also add other creation logic
}
Note that such a creation method may even be in BaseClass itself, or it could be in another class. (If the constructor was private it would need to be in the class itself.)
2) You want an instance of the derived class. (Perhaps you're not supposed to be able to construct the base class. If this is true it probably should be abstract.)
public class Derived : BaseClass { }
public class Foo
{
public void Bar() { Derived d = new Derived();}
}
It's hard to tell from your question if DerivedClass is in the same assembly as BaseClass. If it is, just instantiate the derived class:
BaseClass c = new DerivedClass();
And, like Branko stated, if you have control of the project in which BaseClass lives, you can use InternalsVisibleTo.

Casting generics and the generic type

Consider, I have the following 3 classes / interfaces:
class MyClass<T> { }
interface IMyInterface { }
class Derived : IMyInterface { }
And I want to be able to cast a MyClass<Derived> into a MyClass<IMyInterface> or visa-versa:
MyClass<Derived> a = new MyClass<Derived>();
MyClass<IMyInterface> b = (MyClass<IMyInterface>)a;
But I get compiler errors if I try:
Cannot convert type 'MyClass<Derived>' to 'MyClass<IMyInterface>'
I'm sure there is a very good reason why I cant do this, but I can't think of one.
As for why I want to do this - The scenario I'm imagining is one whereby you ideally want to work with an instance of MyClass<Derived> in order to avoid lots of nasty casts, however you need to pass your instance to an interface that accepts MyClass<IMyInterface>.
So my question is twofold:
Why can I not cast between these two types?
Is there any way of keeping the niceness of working with an instance of MyClass<Derived> while still being able to cast this into a MyClass<IMyInterface>?
This does not work because C# only supports covariance on the type parameters of interfaces and delegates. If your type parameter exists only in output positions (i.e. you only return instances of it from your class and don't accept it as an argument) you could create an interface like this:
interface IClass<out T> { }
class MyClass<T> : IClass<T> { }
Which would allow you to do this:
IClass<Derived> a = new MyClass<Derived>();
IClass<IMyInterface> b = a;
Honestly that is about as close as you are going to get and this requires the C# 4 compiler to work.
The reason you cannot do this in general is because most classes are not simple empty examples. They have methods:
class MyClass<T>
{
static T _storage;
public void DoSomethingWith(T obj)
{
_storage = obj;
}
}
interface IMyInterface { }
class Derived : IMyInterface { }
MyClass<Derived> a = new MyClass<Derived>();
Now, a has a method DoSomethingWith that accepts a Derived and stores it in a static variable of type Derived.
MyClass<IMyInterface> b = (MyClass<IMyInterface>)a;
If that was allowed, b would now appear to have a method DoSomethingWith that accepts anything that implements IMyInterface, and would then internally attempt to store it in a static variable of type Derived, because it's still really the same object referred to by a.
So now you'd have a variable of type Derived storing... who knows what.

Categories

Resources