Многократное наследование во время выполнения с импровизированным интерфейсом
Я пытаюсь заставить работать множественное наследование во время выполнения, используя импровизированный интерфейс, но я застрял, когда хочу передать объект методу.
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: наилучшее перегруженное совпадение методов для MyStuff.PaintWheels(IWheels) имеет несколько недопустимых аргументов
Я пытался разыграть, но получить InvalidCastException
:
paintShop.PaintWheels((IWheels)car);
System.InvalidCastException: невозможно привести объект типа ImpromptuInterface.ActLikeCaster к типу MyStuff.IWheels.
Следующее работает, но я не уверен, что это правильный путь; кажется неоправданным, чтобы преобразовать автомобиль в IWheels
когда IWheels
интерфейс уже должен быть унаследован:
var wheels = Impromptu.CoerceConvert(car, typeof (IWheels));
paintShop.PaintWheels(wheels);
Как правильно достичь множественного наследования во время выполнения с помощью импровизированного интерфейса?
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();
}
}
}