Casting between two types derived from the (same) interface

前端 未结 9 2030
南方客
南方客 2020-12-20 12:55

I have an interface and two types that derive from it.

However, I cannot do the following:

B objectB = (B) objectA

Where B derives

相关标签:
9条回答
  • 2020-12-20 13:24

    An object is assignable to an ancestor (direct or indirect base type) or to an interface it implements, but not to siblings (i.e. another type deriving from a common ancestor); however, you can declare your own explicit conversions:

    class FooObject : IObject
    {
        public string Name { get; set; }
        public int Value { get; set; }
    
        public static explicit operator FooObject(BarObject bar)
        {
            return new FooObject { Name = bar.Name, Value = bar.Value };
        }
    }
    
    class BarObject : IObject
    {
        public string Name { get; set; }
        public int Value { get; set; }
    
        public static explicit operator BarObject(FooObject bar)
        {
            return new BarObject { Name = bar.Name, Value = bar.Value };
        }
    }
    

    Now you can write

    var foo = new FooObject();
    var bar = (BarObject)foo;
    

    or

    var bar = new BarObject();
    var foo = (FooObject)bar;
    

    without getting errors.

    You can also create implicit conversions, if it feels natural. E.g. int is implicitly convertible to double: int i = 5; double x = i;.

    (This is also an answer to the closed question How do I cast Class FooObject to class BarObject which both implement interface IObject?).

    0 讨论(0)
  • 2020-12-20 13:24

    You need to cast as the interface.

    interface IBase { }
    class A : IBase { }
    class B : IBase { }
    

    With this, the only thing the two types have in common is the interface members. B might have items that A does not.

    A a = new A();
    B b = new B();
    
    IBase aBase = a;
    IBase bBase = b;
    

    You can then call anything on the IBase Interface.

    0 讨论(0)
  • 2020-12-20 13:26

    Imagine the following setup:

    public interface Human
    {
        bool Male { get; }
    }
    
    public class Man : Human
    {
        public bool HasABeard { get { return true; } }
    
        public bool IsMale { get { return true; } }
    }
    
    public class Woman : Human
    {
        public bool IsMale { get { return false; } }
    
        public List<Pair<Shoe>> Shoes { get; set; }
    }
    

    What would you expect the compiler to produce from the following code? What will the output be?

    Man a;
    Woman b = new Woman();
    a = (Man)b;
    
    Console.WriteLine(a.HasABeard ? "Beard ON" : "Beard OFF");
    
    0 讨论(0)
  • 2020-12-20 13:31

    When casting from A to B B must be a super type for A or the runtime type of the object must be B

    that is if you have

    class A : B{}
    

    you can cast an object of compile time type A to B. You can also cast a type of B to A if the runtime type of the object is A

    in your case the two types does not share super-subtype relationship. They only share a common super type but that's not sufficient.

    As an example of why this can't work (generically) how would you have the compiler cast from Point[] to a Dictionary<string,HashSet<byte>>? (both implement IEnumerable)

    0 讨论(0)
  • 2020-12-20 13:31

    What you want to do doesn't make sense. objectA is not a B.

    0 讨论(0)
  • 2020-12-20 13:42

    The fact that both types implement the same interface (or have the same base-type, for that matter) does not make them interchangeable; an A is always an A, and a B is always a B. In an inheritance chain, an object can be cast as itself or any parent type. You have:

    A : ISomeInterface
    B : ISomeInterface
    

    which lets you cast an A as A or ISomeInterface, and a B as B or ISomeInterface

    or (depending on your meaning of "derived from")

    SomeBaseType
     > A
     > B
    

    which lets you cast an A as A or SomeBaseType, and a B as B or SomeBaseType

    (plus object, in each case)

    0 讨论(0)
提交回复
热议问题