У меня есть два класса бизнес-контрактов:
public BusinessContract
public Person : BusinessContract
В другом классе у меня есть следующий код:
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = bar;
}
Вышеприведенное даже не скомпилируется, что меня немного сбивает с толку. Я ограничиваю T как BusinessContract, так почему же компилятор не знает, что bar может быть присвоен _foo?
Пытаясь обойти это, мы попытались изменить его на следующее:
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = (Action<BusinessContract>)bar;
}
Теперь компилятор доволен, поэтому я пишу следующий код в другом месте своего приложения:
Foo<Person>( p => p.Name = "Joe" );
И приложение взрывается InvalidCastException во время выполнения.
Я не понимаю. Разве я не могу преобразовать свой более конкретный тип в менее конкретный тип и назначить его?
ОБНОВИТЬ
Джон ответил на вопрос, так что получил одобрение, но просто чтобы закрыть цикл, вот как мы решили проблему.
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = contract => bar( (T)contract );
}
Зачем мы это делаем? У нас есть поддельный DAL, который мы используем для модульного тестирования. С одним из методов нам нужно дать разработчику теста возможность указать, что должен делать метод, когда он вызывается во время теста (это метод обновления, который обновляет кэшированный объект из базы данных). Цель Foo — установить, что должно происходить при вызове обновления. IOW, в другом месте этого класса у нас есть следующее.
public void Refresh( BusinessContract contract )
{
if( _foo != null )
{
_foo( contract );
}
}
Затем разработчик теста может, например, решить, что он хочет установить другое значение имени при вызове Refresh.
Foo<Person>( p => p.Name = "New Name" );
Action<object>
(bar
) переменнойAction<string>
(_foo
), а затем присваиваю значениеFunc<string>
(bar)
Func<object>
переменная (foo
). 20.05.2016