Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
126 views
in Technique[技术] by (71.8m points)

c# - Why is this cast not possible?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...