универсальная функция с ограничением «имеет свойство X»?
У меня есть стороннее приложение с закрытым исходным кодом, которое экспортирует интерфейс COM, который я использую в своем приложении C # .NET через Interop. Этот COM-интерфейс экспортирует многие объекты, которые отображаются как System.Object, пока я не приведу их к соответствующему типу интерфейса. Я хочу назначить свойство всех этих объектов. Таким образом:
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
Но присваивание свойства может (по определенным для приложения причинам, которые неизбежны) генерировать исключения, из которых я хочу восстановить, поэтому я действительно хочу попробовать / поймать каждую из них. Таким образом:
foreach (object x in BigComInterface.Chickens)
{
try
{
(x as Chicken).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
foreach (object x in BigComInterface.Ducks)
{
try
{
(x as Duck).attribute = value;
}
catch (Exception ex)
{
// handle...
}
}
Очевидно, было бы намного чище сделать это:
foreach (object x in BigComInterface.Chickens)
{
SetAttribute<Chicken>(x as Chicken, value);
}
foreach (object x in BigComInterface.Ducks)
{
SetAttribute<Duck>(x as Duck, value);
}
void SetAttribute<T>(T x, System.Object value)
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
Видишь проблему? мойx значение может быть любого типа, поэтому компилятор не может разрешить.attribute, Цыпленок и Утка не находятся в каком-либо дереве наследования, и они не разделяют интерфейс, который имеет.attribute, Если бы они сделали, я мог бы наложить ограничение для этого интерфейса наT, Но так как класс с закрытым исходным кодом, для меня это невозможно.
В моей фантазии я хочу что-то вроде ограничения, требующего аргументаиметь свойство .attribute независимо от того, реализует ли он данный интерфейс. Для остроумия,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
Я не уверен, что делать дальше, кроме как вырезать / вставить этот маленький блок try / catch для каждого из Цыпленка, Утки, Коровы, Овцы и так далее.
Мой вопрос: что является хорошим обходным решением для этой проблемы желания вызвать определенное свойство объекта, когда интерфейс, который реализует это свойство, не может быть известен во время компиляции?