Ну, один из вариантов - просто перегрузить метод Fix()
, чтобы у вас была одна перегрузка для каждого типа, реализующего IFoo
.Но я подозреваю, что вы хотите принять интерфейс напрямую, а не реализовывать типы.
На самом деле вы ищете многократная отправка . Обычно C # /VB использует типы аргумента (ов) для выполнения разрешения перегрузки во время компиляции и динамической диспетчеризации вызова на основе типа времени выполнения экземпляра, для которого вызывается метод.Вам нужно выполнить разрешение перегрузки во время выполнения на основе типов аргументов время выполнения - функция, которую напрямую не поддерживают ни VB.NET, ни C #.
В прошлом я обычно решал эту проблему, используя словарь делегатов, индексированный по System.Type
:
private readonly Dictionary<Type,Action<IFoo>> _dispatchDictionary;
static Bar()
{
_dispatchDictionary.Add( typeof(TextFoo), DoBarTextFoo );
_dispatchDictionary.Add( typeof(AudioFoo), DoBarAudioFoo );
_dispatchDictionary.Add( typeof(VideoFoo), DoBarVideoFoo );
}
public void Fix( IFoo foo )
{
Action<IFoo> barAction;
if( _dispatchDictionary.TryGetValue( foo.GetType(), out barAction ) )
{
barAction( foo );
}
throw new NotSupportedException("No Bar exists for type" + foo.GetType());
}
private void DoBarTextFoo( IFoo foo ) { TextFoo textFoo = (TextFoo)foo; ... }
private void DoBarAudioFoo( IFoo foo ) { AudioFoo textFoo = (AudioFoo)foo; ... }
private void DoBarVideoFoo( IFoo foo ) { VideoFoo textFoo = (VideoFoo)foo; ... }
Однако, как и в C #4, теперь мы можем использовать ключевое слово dynamic
в C #, по сути, делаем то же самое (VB.NET пока не имеет этой возможности):
public void Fix( IFoo foo )
{
dynamic dynFoo = foo;
dynamic thisBar = this;
thisBar.DoBar( dynFoo ); // performs runtime resolution, may throw
}
private void Dobar( TextFoo foo ) { ... /* no casts needed here */ }
private void Dobar( AudioFoo foo ) { ... }
private void Dobar( VideoFoo foo ) { ... }
Обратите внимание, что с помощью ключевого слова dynamic
этот способ имеет цену - он требует, чтобы сайт вызова обрабатывался во время выполнения.Он по существу раскручивает версию компилятора C # во время выполнения, обрабатывает метаданные, захваченные компилятором, выполняет анализ типов во время выполнения и выплевывает код C #.К счастью, DLR может эффективно кэшировать такие сайты вызовов после их первого использования.
Как общее правило, я нахожу оба этих шаблона запутанными, а в большинстве ситуаций избыточными. Если количество подтипов невелико и все они известны заранее, простой блок if/else
может быть намного проще и понятнее.