受保护的泛型类 - 是不是支持?

Posted

技术标签:

【中文标题】受保护的泛型类 - 是不是支持?【英文标题】:Protected generic class - is it supported?受保护的泛型类 - 是否支持? 【发布时间】:2014-03-21 21:00:56 【问题描述】:

我有一个关于 C# 泛型的问题。我希望在我的抽象类中存储一个泛型类型变量,而不在类之外声明该类型。

以下是代码示例。请注意,我不希望将 Param 类暴露在 Calc 类之外。

提前致谢。 - 杜塔。

abstract class Base  

abstract class Calc<T> where T : Base

    protected Param Member; /* how can this be a made a generic declaration 
                             * WITHOUT declaring this class like,
                             * class Calc<T, P> 
                             *      where T : Base
                             *      where P : Param */

    protected Calc(Param p)
    
        this.Member = p;
    

    protected abstract class Param  


class MyBase : Base  

class MyCalc : Calc<MyBase>

    public MyCalc() : base(new MyParam())  

    public void doSomething()
    
        base.Member.A++; // fails on compilation
    

    private class MyParam : Calc<MyBase>.Param
    
        public int A;

        public MyParam()  this.A = 0; 
    

【问题讨论】:

你为什么想要一个受保护的类?你想完成/预防什么?什么不工作?你有什么看起来不错 我需要一个受保护的 Param 类,因为我只希望从 Calc 派生的类能够实例化和调用它的方法。 这与说您不希望 Param 泛型类型参数为“public”不同。 是的,我不想公开。 我的回答对你有用吗?如果是这样,请将其标记为这样。如果没有,请告诉我们原因。谢谢! 【参考方案1】:

你只需要把它转换成新的类型,因为无论如何,变量 Member 被声明为 Param 并且它总是作为 Param 被访问:

((MyParam)base.Member).A++; 

其次,您可以通过以下更改来修复您的 MyParam 类:

MyParam : Calc<MyBase>.Param

到这里:

MyParam : Param

因为通过泛型和继承,Param 已经是Calc&lt;MyBase&gt;

【讨论】:

非常正确——我是这样写的,所以要明确代码。我在该行没有编译错误。 我没有注意到您指出了错误所在。我已经更新了答案以反映我认为您需要做的事情。 Thraka 的更新答案是正确的。只要您不使用泛型,强制转换是必要的。无论如何,用于泛型类型参数的类型必须与泛型类本身具有相同的可见性 - 在您的情况下,与从类中公开参数的方式相同。 虽然选角是我想尽可能避免的事情,但我不能否认这确实是一个前进的方向。感谢 Thraka 和 Lars 试图回答这个问题。我已将此标记为正确答案。【参考方案2】:

Thraka 的回答是正确的:如果您不想使用泛型,则需要强制转换。只是补充一下,以防你真正想做的事情看起来像这样。这是您可以从库中公开的一组类,它们不能被客户端扩展(除非它们以完全信任的方式运行并且可以使用反射等!!)但可以以类型安全的方式使用。

public abstract class SupportedPaymentMethod

    protected internal SupportedPaymentMethod()  


public sealed class Check : SupportedPaymentMethod

    public int CheckNumber  get; private set; 

    public Check(int checkNumber)
     : base()
    
        CheckNumber = checkNumber;
    


public sealed class CreditCard : SupportedPaymentMethod

    public CreditCard()
     : base()
     


public abstract class Payment<T>
    where T : SupportedPaymentMethod

    public T Method  get; private set; 

    protected internal Payment(T method)
    
        Method = method;
    


public sealed CheckPayment : Payment<Check>

    public CheckPayment(Check check)
     : base(check)
     


public sealed CreditCardPayment : Payment<CreditCard>

    public CreditCardPayment(CreditCard creditCard)
     : base(creditCard)
     

客户端(即类库程序集之外的代码)将能够实例化 CheckPaymentCreditCardPayment,但他们将无法创建派生自 Payment&lt;T&gt; 的新类。因此,例如,客户端无法创建CheatingPaymentMethod : Payment&lt;Cheating&gt;。 :)

像您对 base.Member.A++ 的预期调用一样的调用现在可以工作了:

var checkPayment = new CheckPayment(new Check(123456));
var checkNumber = checkPayment.Method.CheckNumber; // Success! :)

【讨论】:

以上是关于受保护的泛型类 - 是不是支持?的主要内容,如果未能解决你的问题,请参考以下文章

Java 泛型泛型简介 ( 泛型类 | 泛型方法 | 静态方法的泛型 | 泛型类与泛型方法完整示例 )

17.scala的泛型类

在 Typescript 的泛型类中初始化泛型类型

将泛型值推送到 Typescript 中泛型类中的泛型列表

只能采用某些类型的泛型类

java 定义泛型类的问题