I have a third-party, closed source application that exports a COM interface, which I am using in my C#.NET application through Interop. This COM interface exports many objects that all show up as System.Object until I cast them to the appropriate interface type. I want to assign an property of all of these objects. Thus:
foreach (object x in BigComInterface.Chickens)
{
(x as Chicken).attribute = value;
}
foreach (object x in BigComInterface.Ducks)
{
(x as Duck).attribute = value;
}
But assigning the property is likely (for application-specific reasons that are unavoidable) to throw Exceptions from which I want to recover, so I really want a try/catch around each one. Thus:
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...
}
}
Obviously, it would be so much cleaner to do this:
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...
}
}
See the problem? My x value can be of any type, so the compiler can't resolve .attribute. Chicken and Duck are not in any kind of inheritance tree and they do not share an interface that has .attribute. If they did, I could put a constraint for that interface on T. But since the class is closed-source, that's not possible for me.
What I want, in my fantasy, is something like a constraint requiring the argument to have the .attribute property regardless of whether it implements a given interface. To wit,
void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
I'm not sure what to do from here other than to cut/paste this little try/catch block for each of Chicken, Duck, Cow, Sheep, and so on.
My question is: What is a good workaround for this problem of wanting to invoke a specific property on an object when the interface that implements that property cannot be known at compile time?
The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.
You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter. The code below constrains a class to an interface.
You can specify one or more constraints on the generic type using the where clause after the generic type name. The following example demonstrates a generic class with a constraint to reference types when instantiating the generic class.
Generic Class T is called type parameter, which can be used as a type of fields, properties, method parameters, return types, and delegates in the DataStore class. For example, Data is generic property because we have used a type parameter T as its type instead of the specific data type.
Well, depending on how humongous your exception handling code is (and if i am not mistaken it could be quite so) using the following trick might help you:
class Chicken
{
public string attribute { get; set; }
}
class Duck
{
public string attribute { get; set; }
}
interface IHasAttribute
{
string attribute { get; set; }
}
class ChickenWrapper : IHasAttribute
{
private Chicken chick = null;
public string attribute
{
get { return chick.attribute; }
set { chick.attribute = value; }
}
public ChickenWrapper(object chick)
{
this.chick = chick as Chicken;
}
}
class DuckWrapper : IHasAttribute
{
private Duck duck = null;
public string attribute
{
get { return duck.attribute; }
set { duck.attribute = value; }
}
public DuckWrapper(object duck)
{
this.duck = duck as Duck;
}
}
void SetAttribute<T>(T x, string value) where T : IHasAttribute
{
try
{
x.attribute = value;
}
catch
{
// handle...
}
}
Unfortunately, this is tricky currently. In C# 4, the dynamic type may help quite a bit with this. COM interop is one of the places that dynamic really shines.
However, in the meantime, the only option that allows you to have any type of object, with no restrictions on interfaces, would be to revert to using reflection.
You can use reflection to find the "attribute" property, and set it's value at runtime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With