具有即兴接口的运行时多重继承

时间:2016-05-07 12:14:11

标签: c# inheritance runtime multiple-inheritance impromptu-interface

我试图使用即兴接口来运行多重继承,但是当我想将对象传递给方法时,我就陷入困境。

public interface IEngine {
    void Foo();
}

public interface IWheels {
    void Foo();
}

public interface IChassie {
    void Foo();
}

public interface IPaintShop {
    void PaintWheels(IWheels wheels);
    void PaintChassie(IChassie chassie);
    void ChromeEngine(IEngine engine);
}

var paintShop = Impromptu.ActLike<IPaintShop>();
var car = Impromptu.ActLike(new [] {typeof(IEngine), typeof(IWheels), typeof(IChassie) } ); 
// dynamic car = Impromptu.ActLike(new [] {typeof(IEngine), typeof(IWheels), typeof(IChassie) } ); // Same error 
paintShop.PaintWheels(car); // RuntimeException as car is dynamic and not the expected IWheels
  

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:最好的   重载方法匹配   &#39; MyStuff.PaintWheels(IWheels)&#39;   有一些无效的论点

我已尝试演员但获得InvalidCastException

paintShop.PaintWheels((IWheels)car);
  

System.InvalidCastException:无法转换类型的对象   &#39; ImpromptuInterface.ActLikeCaster&#39;输入   &#39; MyStuff.IWheels&#39;

以下作品,但我不确定这是正确的方法;当IWheels接口已经被继承时,将汽车转换为IWheels似乎是没有根据的:

var wheels = Impromptu.CoerceConvert(car, typeof (IWheels));
paintShop.PaintWheels(wheels);

使用即兴接口实现运行时多重继承的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

您遇到的问题都与类型安全性有关 - 即使使用Impromptu这样的库,您也必须确保编译器和运行时确保您传入方法的对象是该方法的类型需要。

ActLike<T>可以实现许多接口,但它只返回T的单个类型实例,因此如果没有告诉编译器您的实例实现多个接口的类型,您将被强制转换为必要的接口。

此外,ImpromptuInterface允许您包装一个具有非正式匹配该对象实现的接口的对象,即使接口未正式声明。作为该库的使用者,您仍然必须提供要包装的库的实现。

尝试以下内容:

using System;
using ImpromptuInterface;
using ImpromptuInterface.Dynamic;

namespace Example
{
    public interface IEngine
    {
        void Foo();
    }

    public interface IWheels
    {
        void Foo();
    }

    public interface IChassie
    {
        void Foo();
    }

    public interface IPaintShop
    {
        void PaintWheels(IWheels wheels);
        void PaintChassie(IChassie chassie);
        void ChromeEngine(IEngine engine);
    }

    internal class Program
    {
        public static void Main(string[] args)
        {
            var ps = new
            {
                PaintWheels = ReturnVoid.Arguments<IWheels>(wheels => wheels.Foo()),
                PaintChassie = ReturnVoid.Arguments<IChassie>(chassie => chassie.Foo()),
                ChromeEngine = ReturnVoid.Arguments<IEngine>(engine => engine.Foo())
            };
            var paintShop = ps.ActLike<IPaintShop>();

            var fullCar = new
            {
                Foo = ReturnVoid.Arguments(() => Console.WriteLine("Hello World!"))
            };

            var car = fullCar.ActLike<IEngine>(typeof(IChassie),typeof(IWheels));

            //each of these 3 calls prints "Hello World!" to the console
            paintShop.PaintWheels((IWheels)car);//need to tell the compiler to cast your car to type IWheels because var car is of type IEngine
            paintShop.PaintChassie(car as IChassie);//need to tell the compiler to cast your car to type IChassie because var car is of type IEngine
            paintShop.ChromeEngine(car);//works sans cast because var car is of type IEngine

            //each of these 3 calls prints "Hello World!" to the console, too
            dynamic dynamicCar = car;
            paintShop.PaintWheels(dynamicCar);//by using dynamic you disable the compile time
            paintShop.PaintChassie(dynamicCar);//type checking and the compiler "trusts you" on the typing
            paintShop.ChromeEngine(dynamicCar);//since Impromptu wrapped your object and implemented the interfaces for you, there is no runtime exception

            Console.ReadLine();
        }
    }
}