我可以将泛型类型参数限制为仅接受实现特定通用接口的类型并访问C#中的IF类型参数吗?

时间:2017-03-26 04:49:23

标签: c# generics inheritance syntax generic-constraints

我想要做的是定义一个泛型类型ClassB<TA>,它接受​​TA类型参数被分配任何类型实现通用接口IInterfaceA<TB>无论如何一种方式 [接口定义允许],无论TB实现中传递给它(IInterfaceA)的类型参数TA如何。我还希望能够访问TB中使用的特定IInterfaceA实现已实际传递到TA接口的类型参数(ClassB<TA>)定义。这可能在C#中吗?如果是,那么正确的语法是什么?

E.g。类似下面的内容(虽然看似简单,但我希望不是特别有用)但语法和语义正确:

public interface IInterfaceA<TB>
{
    TB TheProperty {get; set;}
}

public class ClassB<TA> where TA : IInterfaceA<TB>
{
    TA TheProperty {get; set;}

    TB ThePropertyProperty => TheProperty.TheProperty;
}

更新:到目前为止,我实际上已经采用了以下方式(在决定询问是否存在更好的方法之前),包括TBIInterfaceA类型参数)本身在定义中ClassB但我仍然很好奇,如果ClassB可以定义为允许所有IInterfaceA实现并隐式导出/导入IInterfaceA类型参数的方式(不是100%肯定,但似乎实际上做出了逻辑上明确的(非模糊的)强类型感,同时增加了对我的代码重用性,这就是为什么我猜到这样的特征有机会实际存在)。

public class ClassB<TA, TB> where TA : IInterfaceA<TB>
{
    TA TheProperty {get; set;}

    TB ThePropertyProperty => TheProperty.TheProperty;
}

UPDATE2:给出原始示例和现有替代方案的示例,前提是可能值得强调的是,在实例定义时,特定类型意味着(通过实际应用程序设计)分配给TA参数可能发生作为一个非泛型类,一个完全定义的IInterfaceA实现,在其源代码中对TB赋值进行了硬编码(因为在特定情况逻辑部分的上下文中,没有其他类型可以用来代替它,这个特定的类实现了),除了已经没有类型参数(并且我觉得已经定义的内容应该被引用而不是重新定义一个潜在的&#34;我记得它已经被最后一次分配给了X&#34;有点方式,为了清酒至少应该避免为缺陷和错误创造土壤,更不用说美学/可读性,可维护性,消除对针对略有不同情况的逻辑类似物的复制粘贴定义的需求等)。提到的替代解决方案意味着明确定义什么是相当直接的,由编译器明确地弄清楚(至少在相同的接口没有用不同的类型参数实现两次的情况下,感谢@vyrp突出显示模糊的可能性多个实现案例)给定使用上下文(我认为不仅方式更容易,而且更容易出错)并限制通用代码重用机会。我相信这句话可以解释为什么ClassB<TA, TB> where TA : IInterfaceA<TB>语法的一种不那么冗长的替代方法(作​​为实现上述逻辑的一种方式)可以有意义地进行搜索。

2 个答案:

答案 0 :(得分:4)

进行此编译的最直接方法是:

public interface IInterfaceA<T>
{
    T TheProperty {get; set;}
}

public class ClassB<TA, TB> where TA : IInterfaceA<TB>
{
    TA TheProperty {get; set;}

    TB ThePropertyProperty => TheProperty.TheProperty;
}

但我不确定我是否完全遵循你的要求。

我不确定这是否是“更好”的意思,但有时您可以使用静态外部类来推断一个通用参数,同时明确提供另一个:

public static class Helper<TB>
{
    public static ClassB<TA> Create<TA>() where TA : IInterfaceA<TB>
    {
        return new ClassB<TA>();
    }

    public class ClassB<TA> where TA : IInterfaceA<TB>
    {
        TA TheProperty { get; set; }

        TB ThePropertyProperty => TheProperty.TheProperty;
    }
}

答案 1 :(得分:1)

在UPDATE2中,PO说:“直接由编译器明确指出”。

我不同意。

我们假设您有一个这样的课程:

public class Impl : IInterfaceA<int>, IInterfaceA<string>
{
    public int TheProperty { get; set; }
    string IInterfaceA<string>.TheProperty { get; set; }
}

如果您致电ClassB<Impl>,那么TB应该是什么?

话虽如此,让我们深入探讨一种可能的实施方式。

警告:这不是很好的练习代码!它只应该显示语言的机制。 @Enigmativity的答案就是我如何做到(又名ClassB<TA, TB> where TA : IInterfaceA<TB>)。

选项可以是定义基础非通用IInterfaceA。权衡是ThePropertyProperty必须是object

让定义:

public interface IInterfaceA
{
    object TheProperty {get; set;}
}

public interface IInterfaceA<TB> : IInterfaceA
{
    new TB TheProperty {get; set;}
}

public class ClassB<TA> where TA : IInterfaceA
{
    public TA TheProperty {get; set;}

    public object ThePropertyProperty => TheProperty.TheProperty;

    // You can choose to write here either "IInterfaceA`1" or typeof(IInterfaceA<>).Name
    public Type TypeOfTB => typeof(TA).GetInterface("IInterfaceA`1").GetGenericArguments()[0];
}

public class Impl : IInterfaceA<int>
{
    public int TheProperty { get; set; }

    object IInterfaceA.TheProperty
    {
        get { return TheProperty; }
        set { TheProperty = (int)value; }
    }
}

然后以下代码编译并成功运行:

void Main()
{
    var impl = new Impl{ TheProperty = 42 };
    int i = impl.TheProperty;
    Console.WriteLine(i);

    var b = new ClassB<Impl>{ TheProperty = impl };
    i = (int)b.ThePropertyProperty;
    Console.WriteLine(i);

    Console.WriteLine(b.TypeOfTB.Name);
}

输出:

42
42
Int32

对于奖金我已经添加了如何在运行时获得TB。

相关问题