Why is this cast not possible? - c#

interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {}
abstract class FolderOrItem {}
class Folder : FolderOrItem {}
abstract class Item : FolderOrItem {}
class Document : Item {}
now i'm trying to do sth like this:
class Something
{
IFolderItemOrItem<Item> SelectedItem { get; set; }
void SomeMagicMethod()
{
this.SelectedItem = (IFolderOrItem<Item>)GetMagicDocument();
// bad bad bad ... ??
}
IFolderOrItem<Document> GetMagicDocument()
{
return someMagicDocument; // which is of type IFolderOrItem<Document>
}
}
is there any possibility to get this working?

If I read it correctly... then the problem is that just because Foo : Bar, that does not mean that ISomething<Foo> : ISomething<Bar>...
In some cases, variance in C# 4.0 may be an option. Alternatively, there are sometimes things you can do with generic methods (not sure it will help here, though).
The closest you can do in C# 3.0 (and below) is probably a non-generic base interface:
interface IFolderOrItem {}
interface IFolderOrItem<TFolderOrItem> : IFolderOrItem
where TFolderOrItem : FolderOrItem { }
commonly, the base-interface would have, for example, a Type ItemType {get;} to indicate the real type under consideration. Then usage:
IFolderOrItem SelectedItem { get; set; }
...
public void SomeMagicMethod()
{
this.SelectedItem = GetMagicDocument(); // no cast needed
// not **so** bad
}
From the spec, this relates to §25.5.6 (ECMA 334 v4):
25.5.6 Conversions
Constructed types follow the same conversion rules (§13)
as do non-generic types. When applying
these rules, the base classes and
interfaces of constructed types shall
be determined as described in §25.5.3.
No special conversions exist between
constructed reference types other than
those described in §13. In particular,
unlike array types, constructed
reference types do not permit
co-variant conversions (§19.5). This
means that a type List<B> has no
conversion (either implicit or
explicit) to List<A> even if B is
derived from A. Likewise, no
conversion exists from List<B> to
List<object>.
[Note: The rationale for
this is simple: if a conversion to
List<A> is permitted, then apparently,
one can store values of type A into
the list. However, this would break
the invariant that every object in a
list of type List<B> is always a value
of type B, or else unexpected failures
can occur when assigning into
collection classes. end note]
The same applies to interfaces. This changes a bit in C# 4.0, but only in some cases.

As far as the compiler is concerened, IFolderOrItem<Document> & IFolderOrItem<Item> are two completely different types.
Document may inherit Item, but IFolderOrItem<Document> does not inherit IFolderOrItem<Item>
I'm relying on Marc or Jon to post links to the relevant portions of the C# spec.

The problem is that a cast does not work on the generic arguments, but on the class as a whole. Document inherits from Item, true, but IFolderOrItem< Document> does not inherit from IFolderOrItem< Item>, nor is related with it in any way.

An example to understand why it works this way :
Suppose IFolderOrItem exposes a method, for example, void Add(T element).
Your implementation for IFolderOrItem will suppose the parameter is a Document.
But of you cast your IFolderOrItem as IFolderItemOrItem, then someone could call the method Create(T) where T is supposed to be an Item.
The cast from Item to Document is invalid, since an Item is not a Document.
The only way for you to do this is to create a non-generic version of the interface, allowing objects as parameters, the check the type of the object in your implementations.

Related

Generic type and dynamic type for the same property [duplicate]

I am unable to cast a generic type to another generic type, besides the cast should be valid
What I want to archive is in short (for MyModel implementing IModel, and MyImplementation implementing IImplementation):
IImplementation<IModel> implementation = new MyImplementation<MyModel>();
Assert.IsNull(implementation as IImplementation<IModel>);
This is a bit confusing, as the type should be valid.
Complete conceptual model:
interface IModel {}
class MyModel : IModel {}
interface IImplementation<TModel> where TModel : IModel { }
class MyImplementation<TModel> : IImplementation<TModel>
where TModel : IModel { }
public void CallRegister()
{
var implementation = new MyImplementation<MyModel>();
var instance = CastModel(implementation);
Assert.IsNotNull(instance); //this assert fails!
}
private object CastModel<TModel>(IImplementation<TModel> implementation) where TModel : IModel
{
return implementation as IImplementation<IModel>;
}
I need this cast to enable me to save multiple IImplementations to the same Dictionary<Type, IImplementation<IModel>>, where the key is obtained by doing typeof(TModel).
To do this type safe I don't want to use a Dictionary<Type, object>.
Why does the cast fail? Are there additional resources to this? Its a similar question to Invalid Cast of Type Constrained C# Generic, but it is not explained why there just that it does not work.
What is the best way to archive a functionality similar to the dictionary as explained above if this kind of cast is not possible?
Though Olivier's answer gets the idea across about why this usually goes wrong, there is a way to make this work in your program.
The feature you want is called generic interface covariance. Covariance is the property that if a Cat is an Animal, then an IFoo<Cat> is an IFoo<Animal>.
Covariance in C# only works in the following situations:
The "outer" type is an interface, delegate or array. No classes or structs.
If an interface or delegate, the type must be marked at compile time as supporting covariance. Arrays get (unsafe!) covariance for free.
The "inner" types -- the types that are varying -- are both reference types. You can't say that an IFoo<int> is an IFoo<object> even though an int is an object, because they are not both reference types.
To mark an interface as covariant, you put out before the declaration of the type parameter which you wish to allow to vary:
interface IImplementation<out TModel> where TModel : IModel { }
If you do that, your program will start to work.
HOWEVER, out is a reminder to you that covariance is only safe if T is used in output positions. This is legal:
interface I<out T> {
T M();
}
This is not:
interface I<out T> {
void M(T t);
}
In the first, T is only passed out of things. In the second, it is passed in.
In the first scenario, we cannot use covariance to introduce a type hole. We have an I<Cat> and we cast it to I<Animal>, and now M returns an Animal, but that's OK, because we already know that it will return a Cat, and a Cat is an Animal.
But in the second scenario, we have the opposite situation. If we allowed an I<Cat> to be converted to I<Animal> then we have an M that can take a Turtle, but the real implementation can only handle Cats. That's why C# will make this illegal.
So go forth and use covariance, but remember that you have to certify to the compiler that you want it, and that it is safe under all circumstances. If you don't want it, or it is not safe, then you don't get to have covariance, and you'll have to find a different solution to your problem.
This kind of conversion is not allowed for good reasons. Let's take an example where the problem is more obvious. We have the classes Animal, Cat : Animal and Dog : Animal. Now let's do this:
List<Animal> list = new List<Cat>(); // Seems to be possible at first glance.
// An now comes the problem:
list.Add(new Dog()); // Seems to be possible as well.
But wait! The list is in reality a list of cats! And we are trying to add a dog. Even adding new Animal() to list, which is statically typed as List<Animal>, would not work.
Therefore two types T<A> and T<B> are not assignment compatible in C#, even if A and B are!
You need another approach.
What you can do is to wrap your dictionary in a class with a generic method having a generic type constraint.
public class MyImplementationDict
{
private readonly Dictionary<Type, object> _internalDict = new Dictionary<Type, object>();
public void Add<T>(IImplementation<T> item)
where T : IModel
{
_internalDict.Add(typeof(T), item);
}
...
}

convert generic type to base class

public class Base {...}
public class Complex: Base {...}
public class MyOtherClass<T> {...}
and a list of the two type
List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase
I want have a list
listOfComplex.Union(listOfBase)
but i cant convert generic of a type to a generic of another type even if Complex derive fro Base
It's possibble to have a list of a base class?
Although Complex derives from Base, there is no such relationship between MyOtherClass<Complex> and MyOtherClass<Base>. That is the reason why you cannot create an Union of the two lists. For the framework both generic types are completely different.
The solution now really depends on what exactly your class does. Check out the topic of covariance and contravariance here in Docs - these are two special cases in which you will be permitted to create conversions between the two generic types if the types either are input or output only.
You could also add custom cast or manually cast the items to the "base" type before doing the "union" operation.
Because that's how Covariance and Contravariance in Generics works, specifically invariance, it means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.
You can't assign an instance of List<Base> to a variable of type List<Complex> or in the opposite direction. Same applies to custom generic classes. There is no implicit conversion that compiler could use in order to convert types.
Even if you add generic type constraint. A<B> and A<C> are two different types with no conversion between them even if C is inherited from B (because AC is not inherited from AB)
#MartinZikmund has explained why it does not work. The resolution to this kind of problem is to either derive the generic classes from a non-generic base class or to let them implement a common interface.
public class MyOtherClassBase { }
public class MyOtherClass<T> : MyOtherClassBase { }
Then you can specify MyOtherClassBase as generic parameter to Union explicitly. Now, Union will expect inputs of type IEnumerable<MyOtherClassBase>. Lists of type List<MyOtherClass<T>> are assignment compatible to IEnumerable<MyOtherClassBase>.
var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);
Note the out keyword in the declaration
public interface IEnumerable<out T> : System.Collections.IEnumerable
It makes the interface covariant. See also SO question <out T> vs <T> in Generics and especially Reed Copsey's answer.
You should specify in your generic that T is a class base on Type :
public class MyOtherClass<T> where T : Base {...}
T will be accepted only if derive from Base And Union will should work
Here some documentation about Generics, thanks to #Marie:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

Why does this interface have to be explicitly implemented?

Coming back to C# after a few years so I'm a little rusty. Came across this (simplified) code and it's leaving my head scratching.
Why do you have to explicitly implement the IDataItem.Children property? Doesn't the normal Children property satisfy the requirement? After all, the property is used directly to satisfy it. Why is it not implicit?
public interface IDataItem {
IEnumerable<string> Children { get; }
}
public class DataItem : IDataItem {
public Collection<string> Children { get; } = new Collection<string>();
// Why doesn't 'Children' above implement this automatically?!
// After all it's used directly to satisfy the requirement!
IEnumerable<string> IDataItem.Children => Children;
}
According to the C# source, here's the definition of Collection<T>:
[System.Runtime.InteropServices.ComVisible(false)]
public class Collection<T> :
System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>, <-- Right Here
System.Collections.Generic.IList<T>,
System.Collections.Generic.IReadOnlyCollection<T>,
System.Collections.Generic.IReadOnlyList<T>,
System.Collections.IList
As you can see, it explicitly implements IEnumerable<T> and from my understanding, if 'X' implements 'Y' then 'X' is a 'Y', so Collection<String> is an IEnumerable<String> so I'm not sure why it isn't satisfied.
Perhaps this example makes it clearer. We want signatures to match exactly1,2, no substitutions allowed, despite any inheritance relationships between the types.
We're not allowed to write this:
public interface IDataItem {
void DoStuff(string value);
}
public class DataItem : IDataItem {
public void DoStuff(object value) { }
}
Your example is the same, except your asking for return types rather than parameters (and employing a narrowing rather than widening conversion, for obvious reasons). Nontheless, the same principal applies. When it comes to matching signatures, the types must match exactly3.
You can ask for a language that would allow such things to happen and such languages may exist. But the fact of the matter is, these are the rules of C#.
1Outside of some limited support for Co- and Contra-variance involving generics and interfaces/delgates.
2Some may argue about whether signature is the right word to use here since in this case, return types matter as much as parameter types, generic arity, etc; In most other situations where someone talks about C# method signatures, they'll be explicitly ignoring the return type because they're (explicitly or implicitly) considering what the overloading rules say, and for overloading, return types are not part of the signature.
Nonetheless, I'm happy with my usage of the word "signature" here. Signatures aren't formally defined in the C# specification and where it's used, it's often to point out which parts of the signature aren't to be considered for overloading.
3Not to mention the issues that would be raised if your Children method was returning a struct that happened to implement IEnumerable<string>. Now you've got a method that returns the value of a value type and a caller (via the IDataItem interface who is expecting to receive a reference to an object.
So it's not even that the method could be used as-is. We'd have to (in this case) have hidden boxing conversions to implement the interface. When this part of C# was specced, they were, I believe, trying not to have too much "hidden magic" for code you could easily write yourself.
In your example your "normal" Children property do not actually satisfy the interface requirement. The type is different. It does not really matter that you can cast it - they are different.
Similar example and maybe a bit more obvious is if you would implement an interface with a actual method that returns IEnumerable and tried an ICollection method from the actual class. There is still that compile time error.
As #Ben Voigt said the conversion still generates some code, and if you want to have it - you need to add it implicitly.
The question has been answered here (you have to match the interface types) and we can demonstrate the problem with an example. If this worked:
public interface IDataItem {
IEnumerable<string> Children { get; set; }
void Wipe();
}
public class DataItem : IDataItem {
public Collection<string> Children { get; } = new Collection<string>();
public void Wipe() {
Children.ClearItems(); //Property exists on Collection, but not on IEnumerable
}
}
And we then use this code like this:
IDataItem x = new DataItem();
//Should be legal, as Queue implements IEnumerable. Note entirely sure
//how this would work, but this is the system you are asking about.
x.Children = new Queue<string>();
x.Wipe(); // Will fail, as Queue does not have a ClearItems method within
Either you mean the property to only ever be enumerable, or you need the properties of the Collection class - type your interface appropriately.
Any class that implements the interface must contain the definition for method that matches the signature that the interface specifies. The interface defines only the signature. In that way, an interface in C# is similar to an abstract class in which all the methods are abstract.
Interfaces can contain methods, properties, events, indexers, or any combination of those four member types.
Here is the good read about interfaces.
Interfaces in C#
Hope it will help you in further understanding.

Why does XmlSerializer require types which inherit from IEnumerable to have an implementation of Add(System.Object)?

I am using xml serialization but now came across a runtime error I haven't seen before.
"To be XML serializable, types which
inherit from IEnumerable must have an
implementation of Add(System.Object)
at all levels of their inheritance
hierarchy. ImageEditor.EffectOptions
does not implement Add(System.Object)"
It seems a little weird to be forced to implement a method via runtime exception, rather than compile time error such as missing methods from implemented interfaces.
Is this by design? Should this not be enforced via some sort of interface like XmlSerializable, etc?
Other than this I am wondering if the serializer guarantees passing a value of the right type where I can just cast it to the type, which in my case is EffectOption.
Or should I implement this Add (object) method to see if the object is of type EffectOption and if not throw an exception?
I haven't implemented this Add (object) method before but my guess is it's safer to just cast it to EffectOption and add it to EffectOptions collection.
EDIT: Here's the type itself:
public class EffectOptions : IEnumerable<EffectOption>
{
public List<EffectOption> Options { get; private set; }
//IEnumerable methods
}
Because sub classes implicitly implement interface methods because of the base class but xmlserializer is using reflection and that is why you get the error at runtime and not compile time.
Try explicitly implementing and see what happens. I have not had this issue before so I'm not sure why you are unless you're doing something custom.
If you have your sub classes explicitly implementing the interface but not doing any implementation code (letting the implicit implementation of methods happen) then remove the interface from your sub type declaration as it should still be valid due to your base type. (someone tell me if i'm off here)
I've just run into this issue and solved it by adding an add method:
public class EffectOptions : IEnumerable<EffectOption>
{
public List<EffectOption> Options { get; private set; }
public void Add(object o){
this.Options.Add(o as EffectOption); //you may want to extend the code to check that this cast can be made,
//and throw an appropriate error (otherwise it'll add null to your list)
}
//IEnumerable methods
}
I hope this helps.

Casting Problem within generic types but the same types

The interface:
interface IPlay<T> { }
Classes:
class Mp3Player : IPlay<int> { }
class OggPlayer : IPlay<double> { }
class DummyPlayer : IPlay<object> { }
Trying to use :
1. IPlay<object> player = new Mp3Player ();
2. IPlay<int> player2 = new OggPlayer ();
A Big why 1 and 2. usages can not cast?
int to object, or, int to double. It's possible in nongeneric cases. Is there any other method?
You are trying to perform invalid casts. The Mp3Player is not an IPlay<object>, it is an IPlay<int>. Your OggPlayer is an IPlay<double>, not an IPlay<int>. You can't cast an IPlay<int> to an IPlay<object> or an IPlay<double> to an IPlay<int> like that. They don't inherit from each other, and because they are generic, they are distinct types strongly differentiated from each other.
In C# 4.0 such implicit casts might, and I stress MIGHT, be possible, due to the improved co/contra variance it will have. But generally speaking, such implicit casts across distinct type boundaries are not possible.
Imagine:
interface IPlay<T>
{
T GetSomething();
DoSomething(T value);
}
So, when using:
IPlay<object> player = new Mp3Player();
Then GetSomething() may be type safe, but how about DoSomething(object value)? ... That call cannot guarantee the logic will work on an object, since the player expects ints.
Note that .NET 4 has a mechanism to indicate the variance of an interface, so that you can mark the interface as only using T as return values, in which case at least your first assignment will work.
Note however that regardless, the second (IPlay<int> player2) will not work, because there is no inheritance relationship between double and int. Being able to cast values implicitly is not the same thing as inheritance.
What you are looking to do is called covariance and this feature will be supported in C# 4 on interface types.
Here is a good talk by Anders Hejlsberg from PDC where he describes how co/contravariance will work in C# 4.0 (among other things).
There's a common misconception that IPlay<T> generates a common ancestor, which would be IPlay<object>. This might be valuable, but it is not true.
You must generate and name the common ancestor yourself:
interface IPlay {}
interface IPlay<T> : IPlay {}

Categories