Casting a generic element type downwards - c#

public class ConfigControlBase<T> : UserControl
where T : ProviderBase
{
public T Provider { get; set; }
public void Init(T provider)
{
this.Provider = provider;
}
}
public abstract class ProviderBase
{
public abstract ConfigControlBase<ProviderBase> GetControl();
}
public class ProviderXConfigControl : ConfigControlBase<ProviderX>
{
}
public class ProviderX : ProviderBase
{
public override ConfigControlBase<ProviderBase> GetControl()
{
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;
return confControl;
}
}
return confControl; throws an exception:
Cannot implicitly convert type ConfigControlBase<ProviderX> to ConfigControlBase<ProviderBase>

Let's change the name of your classes and properties, but keep the shape the same:
public class Cage<T> where T : Animal
{
public T Contents { get; set; }
}
public class Aquarium : Cage<Fish> { }
public abstract class Animal
{
public abstract Cage<Animal> GetCage();
}
public class Fish : Animal
{
public override Cage<Animal> GetCage()
{
return (Cage<Animal>)(new Aquarium());
}
}
Now is it clear why this is not legal? Suppose it were legal. Then you could do this:
Fish fish = new Fish();
Cage<Animal> cage = fish.GetCage();
cage.contents = new Tiger();
And now you have a tiger in your aquarium. And no one wants that.
The compiler (or runtime) has to prevent this type error somehow; it chooses to prevent it as soon as possible. The earliest it can do so is on the type test for the conversion from Aquarium to Cage<Animal>. The compiler knows that this can eventually lead to tigers in aquariums, so it does not allow the conversion at all. If you force the compiler to allow it through casts then it fails at runtime.

Generic types with assignable type arguments are not assignable themselves.
For instance, you cannot cast List<string> to List<object>, although string is an object.
It is not immediately obvious why such casting is not supported so let me give you an example:
var words = new List<string> { "Serve God", "love me", "mend" };
var objects = (List<object>) words; // C# compiler wouldn't allow this
objects.Add (new Car()); // we just added a Car to Shakespeare's work and the universe exploded
C# doesn't encourage universe explosion, however since C# 4.0 a light version of this idea is implemented. You see, in some cases such casting would actually be safe.
.NET 4.0 brings concepts of covariance and contravariance in generics only for interfaces and delegates, you may want to check this out.
Example (doesn't work prior to .NET 4.0):
void HandleCollection (IEnumerable<object> collection)
{
// ...
}
var words = new List<string> { "Serve God", "love me", "mend" };
// IEnumerable is defined as IEnumerable<out T> in .NET 4.0
// 'out' keyword guarantees that T is only used for return values
// and therefore client code can't explode the universe
var objects = (IEnumerable<object>) words;
HandleCollection (objects);

This is because ConfigControlBase<ProviderX> is not a ConfigControlBase<ProviderBase>

your
public override ConfigControlBase<ProviderBase> GetControl()
doesn't match
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;

This answer might not be useful in your scenario, as you should probably look for another solution, but during reflection I found the ability to cast to less generic types very useful, hence I wrote a solution for it. It only works for interfaces however, and you do have to guarantee you will only pass objects of the correct types to the interface.
I basically generate a proxy class at runtime which does all the required casts for you. It's usage looks as follows:
object validator; // An object known to implement IValidation<T>.
object toValidate; // The object which can be validated by using the validator.
// Assume validator is IValidation<string> and toValidate a string.
IValidation<object> validation
= Proxy.CreateGenericInterfaceWrapper<IValidation<object>>( validator );
validation.IsValid( toValidate ); // This works! No need to know about the type.
// The following will throw an InvalidCastException.
//validation.IsValid( 10 );
More information and source code can be found on my blog.

Related

Inferring generics from parent class in method signature fails

I'm using a library with (hundreds of, template-generated) classes without generic modifier, each extending the same classes with generic modifier (essentially to shorten the notation). E.g.
class DArr : NumberObject<double, MyArrayIndexer> { ... }
class IArr : NumberObject<int, MyArrayIndexer> { ... }
class DMat : NumberObject<double, MyMatrixIndexer> { ... }
class IMat : NumberObject<int, MyMatrixIndexer> { ... }
class BMat : NumberObject<bool, MyMatrixIndexer> { ... }
and so on
I now want to write functions that proccess these with a function that requires their internal type (e.g. internal copies that need to know whether we have 4 or 8 bytes per element, and what type of Indexer is being used). I therefore made the signature of my function:
public SomeUnrelatedClass<T> Process<T,TVal,T0>(SomeUnrelatedClass<T> obj) where T : NumberObject<TVal,T0> {
//here some tstuff that requires T, TVal and T0
}
but unfortunately it seems I can't use it in the way I need to, i.e.
SomeUnrelatedClass<DArr> input = ...;
SomeUnrelatedClass<DArr> output = Process(input);
since it fails to derive TVal and T0 from (why??), despite it being uniquely determined. How can I remedy this? Calling it as SomeUnrelatedClass<DArr> output = Process<DArr,double,MyArrayIndexer>(input); is not an option because in reality there's a lot more of these generics and they're a lot longer in name (and this function will be used thousands of times in future code, so I'd much rather now write a more complicated function that does it right and keeps the syntax simple). Ideally I'd not do a long list of "if type == ..." though, because the list of types is template-generated and changes over time as types get added (meaning this template would be dependent on the other template, etc.)
I've thought of silly hacks like making the syntax Process<T,TVal,T0>(SomeUnrelatedClass<T> obj,SomeUnrelatedClass<NumberObject<TVal,T0>> sameObj) and calling SomeUnrelatedClass<DArr> output = Process(input,input); but I feel like that's just a really poor fix. What's a more 'proper' way to do this?
I think you might be in some luck here, because C# does not infer types based on the constraints that you specify. I think it's part of the specification, from what I could dig out. But you might be able to solve you problem anyway :) - I managed to get the following running.
{
var input = new DArr(12.34);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
{
var input = new IArr(42);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
// Generated output:
//
// Type [DArr] with value 12,34
// Type [IArr] with value 42
So no matter how many types you define that Process method will consume and map the input to the right concrete type.
Below is how this could work:
public class NumberObject<TType, TIndexer>
{
public NumberObject(TType type) { MyType = type; }
public TType MyType { get; }
}
public class MyArrayIndexer { }
public class DArr : NumberObject<double, MyArrayIndexer>
{
public DArr(double value) : base(value) { }
}
public class IArr : NumberObject<int, MyArrayIndexer>
{
public IArr(int value) : base(value) { }
}
public class SomeUnrelatedClass<T>
{
public T Obj { get; }
public SomeUnrelatedClass(T obj){ Obj = obj; }
}
public class Visitor
{
public static SomeUnrelatedClass<NumberObject<TVal, T0>> Process<TVal, T0>(NumberObject<TVal, T0> input)
{
return new SomeUnrelatedClass<NumberObject<TVal, T0>>(input);
}
}
The trick here is to reduce the number of generic parameters - getting rid of the T type as it can directly be expressed by the remaining two as you actually also write yourself
T is NumberObject<TVal, T0>
When the level of types to infer is reduced the C# compiler can determine them directly and viola you can leave you specifying generic parameters to the Process method.

Cast array of unknowClass to array of otherClass in c#

How Can I dynamically cast at runtime.That is I am passing a child class object in the parent class object.
public abstract class tObject
{
public tObject[] someMthode(){;}
}
public class myClass : tObject
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
I want
myClass mc=new myClass();
tObject to=mc;
myClass[] mcArray=(myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
but when check any element of mcArray is correct
if (mcArray[0] is myClass)
{
//return true and run this ;
}
In fact I want cast when a method return array of tObject according to the base class :
subClass[] mcArray=(subClass[])instanceOfsubClass.someMthode()
subClass or myClass and ... are unknown class , and i don't know theirs name.
Solution
public T[] Cast<T>(tObject[] mcArray ) where T : tObject
{
if (mcArray != null)
{
int cnt = mcArray.GetLength(0);
T[] t = new T[cnt];
for (int i = 0; i < cnt; i++)
{
t[i] = (T)mcArray[i];
}
return t;
}
return null;
}
Thanks all for replies.
C# does not support that kind of array conversion. C# does -- unfortunately! -- support dangerous array covariance. That is, if you had an array myClass[] then you could implicitly convert it to an array tObject[]. This means that you can do this:
Tiger[] tigers = new Tiger[10];
Animal[] animals = tigers;
animals[0] = new Turtle();
and now we have a turtle inside an array of tigers. This crashes at runtime.
That's bad enough, but you want it to go the other way -- I have an array of animals and I'd like it to be treated as an array of tigers. That does not work in C#.
As other answers have noted, you'll need to make a second array and copy the contents of the first to the second. There are a number of helper methods to do so.
Maybe?
myClass mc = new myClass();
tObject to = mc;
//myClass[] mcArray = (myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
var mcArray = Array.ConvertAll(mc.someMthode(), item => (myClass) item);
Well, you can call IEnumerable.Cast for that:
var myArr = mc.someMethod().Cast<MyClass>().ToArray();
As MyClass[] implements IEnumerable<MyClass>.
EDIT: What you want is quite dangerous. Look the following code:
subClass[] mcArray=(subClass[]) new BaseClass[] {...};
If this conversion would work we could now simply make the following also:
mcArray[0] = new AnotherClass();
Now you have an array of subClasses containin one item of AnotherClass also.
If you do not know the type at compile-time you cannot expect the compiler to provide any compile-time-logic for a type it doesn´t know. Thus casting to an unknown type and calling members on isn´t supported. However you may achieve this using reflection:
var runtimeType = myArr[0].GetType();
var mi = runtimeType.GetMethod("SomeMethod");
var value = mi.Invoke(myArr[0]);
This is similar to the call
var value = ((subClass)myArr[0]).SomeMethod();
Why not solve it one step up the chain and make someMethod (spelling corrected) generic:
public abstract class tObject<T> where T:tObject
{
public T[] someMethod(){;}
}
public class myClass : tObject<myClass>
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
now myClass.someMethod returns a myclass[] and that problem is solved. However, since I'm assuming that tObject does other things that just create an array of tObjects, it may cause other problems that aren't inferrable from the code you provided.
Plus it's not 100% foolproof. There's nothing stopping you (or someone else) from defining:
public class myWeirdClass : tObject<myClass>
{
}
now myWeirdClass.someMethod also returns a myClass[], and the pattern is broken. Unfortunately there's no generic constraint that requires that the generic parameter be the defining class itself, so there's no way to prevent this flaw at compile-time.
Another option may be to move the array creation outside of the class itself, since it is a code smell in itself:
public class ObjectFactory<T> where T:tObject
{
public T[] SomeMethod()
{
... create an array of Ts
}
}

Casting between classes with generics

Can someone please explain why this code snippet is not working? Why is a not castable to b?
I was thinking about covariance and contravariance but as far as I'm concerted this is not applicable to abstract classes.
Compile Error:
Cannot convert type 'ConsoleApplication1.SVM' to 'ConsoleApplication1.VMSBase' ConsoleApplication1\Program.cs
class Program
{
static void Main(string[] args)
{
var a = new SVM();
var b = (VMSBase<Model>)a;
}
}
class SVM : VMSBase<SpecialModel>
{
}
class VMSBase<TS> : VMBase<TS> where TS : Model
{
}
class VMBase<T> where T : Model
{
}
class SpecialModel : Model
{
}
class Model
{
}
SVM is a subtype of VMSBase<SpecialModel>, so it can be converted to one.
But there's no polymorphic relationship between VMSBase<SpecialModel> and VMSBase<Model>, because the generic type parameter T in VMSBase<T> is invariant.
In order for VMSBase<X> to be a subtype of VMSBase<Y> (where X is a subtype of Y), T has to be covariant. You mark it as covariant using the out keyword: VMSBase<out T>. This, however, forces you to use the type T only for return values from all members (methods, properties, etc) and never as an input value (method arguments).
There's another catch: c# only allows variance on interfaces. So you'll have to change both VMBase and VMSBase to be interfaces.
class Program
{
static void Main(string[] args)
{
SVM a = new SVM();
var b = a as IVMSBase<Model>;
}
}
class SVM : IVMSBase<SpecialModel> {}
interface IVMSBase<out TS> : IVMBase<TS> where TS : Model {}
interface IVMBase<out T> where T : Model {}
More info: Covariance and Contravariance FAQ
Bottom line is that VMSBase<SpecialModel> is not the same as VMSBase<Model>.
This is the same reason why this won't compile:
List<ViewBase> list = new List<GridView>();
Although GridView inherits from ViewBase.
It's just how the language works, a limitation of generics you might say.
Imagine you could legally do the cast. Now imagine we have this method defined that eats models:
class VMSBase<TS> : VMBase<TS> where TS : Model
{
public void GobbleUpModel(TS model)
{
}
}
Using this, we can now bypass type-safety in the following (surprising if you haven't seen it before) manner:
//SpecialModel2 is some other subclass of Model, not related to SpecialModel
SpecialModel2 incompatibleModel;
var a = new VMSBase<SpecialModel>();
var b = (VMSBase<Model>)a;
//forces a to gobble up a model that is incompatible with SpecialModel
b.GobbleUpModel(incompatibleModel);
The reason why generics are not variant in C# is because it could cause typing problems: using your example, assume that VMSBase has a property of type T named MyProperty. If the casting was possible, you would be able to do something like:
var a = new VMSBase<SpecialModel>();
var b = (VMSBase<Model>) a;
b.MyProperty = new Model();
Now you just set the value of b.MyProperty to an instance of a Model; but that is not consistent with the type expected in VMSBase, which is actually SpecialModel.

C# covariance structure understanding?

Assuming
class A
{ }
class B : A
{ }
covariance is not supported for generic class.
Meaning - we cant do something like this :
MyConverter<B> x1= new MyConverter<B>();
MyConverter<A> x2= x1;
Thats fine and understood.
From my reading - i understand that Covariance will be available:
"If you use a backing Generic Interface Being implemented on a Generic Class - so that access to the T type object instance will be available through those interfaces ".
I have just one problem.
Ive seen many examples of the "converter" class as a form of Stack .
But never understood " what if I want to use only 1 instance of B from a reference of A ? "
so Ive tried some code :
Create B object + values ---> use Generic Converter for B --->
use the covariance flow to get its A reference ---> now you can use it
either as A or as B.
My question :
Is That the correct way of doing this ( for using covariance for 1 object only ) ?
p.s.
The code is working and compiled ok. http://i.stack.imgur.com/PJ6QO.png
Ive been asking /reading a lot about this topic lately - I dive into things in order to understand them the best I can.
Your code compiles and works, so is it "correct"? I guess it is!
However it is not very interesting having a stack that only contains a single element; that's not really a stack. Let's think about how you might make a truly covariant and contravariant stack.
interface IPush<in T> { void Push(T item); }
interface IPop<out T> { T Pop(); }
class Stack<T> : IPush<T>, IPop<T>
{
private class Link
{
public T Item { get; private set; }
public Link Next { get; private set; }
public Link(T item, Link next) { this.Item = item; this.Next = next; }
}
private Link head;
public Stack() { this.head = null; }
public void Push(T item)
{
this.head = new Link(item, this.head);
}
public T Pop()
{
if (this.head == null) throw new InvalidOperationException();
T value = this.head.Item;
this.head = this.head.Next;
return value;
}
}
And now you can use the stack covariantly for popping, and contravariantly for pushing:
Stack<Mammal> mammals = new Stack<Mammal>();
IPop<Animal> animals = mammals;
IPush<Giraffe> giraffes = mammals;
IPush<Tiger> tigers = mammals;
giraffes.Push(new Giraffe());
tigers.Push(new Tiger());
System.Console.WriteLine(animals.Pop()); // Tiger
System.Console.WriteLine(animals.Pop()); // Giraffe
What if I want to use only one instance of B from a reference of A?
Your question is "what if I want to use a Tiger but I have a reference an Animal?" The answer is "you can't" because the Animal might not be a Tiger! If you want to test whether the reference to Animal is really a tiger then say:
Tiger tiger = myAnimal as Tiger;
if (tiger != null) ...
or
if (myAnimal is Tiger) ...
What about if you want to convert class C<B> to C<A>?
That's not possible. There is no reference conversion there. The only covariant and contravariant reference conversions in C# 4 are on generic interfaces and generic delegates that are constructed with reference types as the type arguments. Generic classes and structs may not be used covariantly or contravariantly. The best thing you can do is make the class implement a variant interface.
It looks like you're using the converter simply to get a reference of type A pointing to an object of type B. There's a much easier way to do that, called casting:
B b = new B();
A a = (A)b;
In fact, since A is a superclass of B, the conversion is implicit:
B b = new B();
A a = b;
Your program could be:
class Program
{
static void Main(string[] args)
{
B b = new B { b1 = 22222 };
A a = b;
Console.WriteLine(a.a1);
Console.WriteLine(((B)a).b1);
}
}
IPushable<B> x1 = new MyConverter<B>();
x1.Set(b);
// I believe this is valid.
IPoppable<A> final = x2;
You can find some great examples and descriptions of it on this blog.

Type parameters, constraints and covariance/contravariance

Let's say I have the following classes that have different implementations based on the object to be stored in:
public class ListOfPersistent<T> :
IList<T> where T : Persistent {... implementation ...}
public class ListOfNonPersistent<T> :
IList<T> {... implementation ...}
And I want to use one of another version on the above classes by doing something like this:
public class PersistentList<T> : IList<T> {
protected PersistentList() {
if (list != null) {
return;
}
if (Extensions.IsPersistent<T>()) {
list = new ListOfPersistent<T>();
} else {
list = new ListOfNonPersistent<T>();
}
}
protected IList<T> list;
....
}
Of course the above does not compiles, because there is a type constrain on the first class and none on the second. Is there any way I can: Tell the compiler that it should not check the constrain on this specific case (list = new ListOfPersistent<T>()) because I KNOW it will be of that type, or do some covariance/contravariance magic so the code compiles without any issues?
Covariance and contravariance won’t help you here because IList<T> is invariant.
Personally I would argue that you have a flaw in your class design. You shouldn’t want to instantiate a ListOfPersistent<T> and then place it in a variable whose type, IList<T>, is incompatible. Unfortunately I cannot suggest a good alternative because I have no idea how you are planning to use these classes or what your overall goal is; but I can make a suggestion with a disclaimer that it is hacky and should probably only be used if you really know what you are doing:
public static class ListUtils
{
public static object CreateListOfPersistent(Type elementType)
{
if (!typeof(Persistent).IsAssignableFrom(elementType))
throw new ArgumentException("elementType must derive from Persistent.", "elementType");
var listType = typeof(ListOfPersistent<>).MakeGenericType(elementType);
return Activator.CreateInstance(listType);
}
}
// ...
if (Extensions.IsPersistent<T>())
list = (IList<T>) ListUtils.CreateListOfPersistent(typeof(T));
else
list = new ListOfNonPersistent<T>();

Categories

Resources