具有"具有属性X"约束的泛型函数?

cat*_*ood 16 c# generics properties interface

我有一个第三方闭源应用程序,它导出一个COM接口,我通过Interop在我的C#.NET应用程序中使用它.此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;
}
Run Code Online (Sandbox Code Playgroud)

但是分配属性很可能(由于特定于应用程序的原因,这是不可避免的)抛出我想要恢复的异常,所以我真的想要一个try/catch.从而:

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...
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这样做会更加清晰:

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...
    }
}
Run Code Online (Sandbox Code Playgroud)

看到问题?我的x值可以是任何类型,因此编译器无法解析.attribute.Chicken和Duck不在任何类型的继承树中,并且它们不共享具有.attribute的接口.如果他们这样做,我可以在T上为该接口设置约束.但由于课程是闭源的,这对我来说是不可能的.

在我的幻想中,我想要的是类似约束,要求参数具有.attribute属性,无论它是否实现给定的接口.以机智,

void SetAttribute<T>(T x, System.Object value) where T:hasproperty(attribute)
Run Code Online (Sandbox Code Playgroud)

除了为Chicken,Duck,Cow,Sheep等每个切割/粘贴这个小的try/catch块之外,我不知道该怎么做.

我的问题是:当在编译时无法知道实现该属性的接口时,想要在对象上调用特定属性的问题有什么好的解决方法?

gha*_*.st 6

好吧,取决于您的异常处理代码是多么庞大(如果我没有错,那可能就是这样),使用以下技巧可能会对您有所帮助:

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...
    }
}
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 5

不幸的是,目前这很棘手。在 C# 4 中,动态类型可能对此有很大帮助。COM 互操作是动态真正发挥作用的地方之一。

但是,与此同时,允许您拥有任何类型的对象且对接口没有限制的唯一选择是恢复使用反射。

您可以使用反射来查找“属性”属性,并在运行时设置它的值。