-2

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

例如,类似以下的内容(我希望虽然看似说明性但不是特别有用)但在语法和语义上是正确的:

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;
}

更不用说美学/可读性、可维护性、消除对针对略有不同情况的逻辑类似物的复制粘贴定义的需求等)。提到的替代解决方案意味着明确定义什么是相当直接的,以便由编译器明确地计算出来(至少在相同的接口没有使用不同类型参数实现两次的情况下,感谢@vyrp 强调了歧义的可能性多重实现案例)给定使用上下文(我认为这不仅是一种更方便的方式,而且更不容易出错)并限制了通用代码重用的机会。我相信这句话可以解释为什么一个不那么冗长的替代方案 提到的替代解决方案意味着明确定义什么是相当直接的,以便由编译器明确地计算出来(至少在相同的接口没有使用不同类型参数实现两次的情况下,感谢@vyrp 强调了歧义的可能性多重实现案例)给定使用上下文(我认为这不仅是一种更方便的方式,而且更不容易出错)并限制了通用代码重用的机会。我相信这句话可以解释为什么一个不那么冗长的替代方案 提到的替代解决方案意味着明确定义什么是相当直接的,以便由编译器明确地计算出来(至少在相同的接口没有使用不同类型参数实现两次的情况下,感谢@vyrp 强调了歧义的可能性多重实现案例)给定使用上下文(我认为这不仅是一种更方便的方式,而且更不容易出错)并限制了通用代码重用的机会。我相信这句话可以解释为什么一个不那么冗长的替代方案 感谢@vyrp 强调了在多个实现案例中可能存在歧义)给定使用上下文(我认为这不仅是一种更方便的方式,而且更不容易出错)并限制了通用代码重用的机会。我相信这句话可以解释为什么一个不那么冗长的替代方案 感谢@vyrp 强调了在多个实现案例中可能存在歧义)给定使用上下文(我认为这不仅是一种更方便的方式,而且更不容易出错)并限制了通用代码重用的机会。我相信这句话可以解释为什么一个不那么冗长的替代方案ClassB<TA, TB> where TA : IInterfaceA<TB>语法(作为实现上述逻辑的一种方式)完全可以搜索。

4

2 回答 2

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;
    }
}
于 2017-03-26T04:59:30.257 回答
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。

于 2017-03-26T07:40:14.790 回答