2

重複の可能性:
派生クラスの List<> を基本クラスの List<> にキャストする

タイトルの意味がよくわからないかもしれません。コードを参照してください。

class Person {}

class Manager : Person {}

class PaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}

class Calculators : List<PaymentCalculator<Person>>
{
    public Calculators()
    {
        this.Add(new PaymentCalculator<Person>());
        this.Add(new PaymentCalculator<Manager>());     // this doesn't work

        PassCalculator(new PaymentCalculator<Person>());
        PassCalculator(new PaymentCalculator<Manager>());   // this doesn't work
    }

    public void PassCalculator(PaymentCalculator<Person> x)
    { }
}

「これは機能しません」とマークされたコードの 2 行はコンパイルされません。

問題を回避できますが、私の意図が間違っているようには見えません。またはそれは?

4

2 に答える 2

1

そうです。「デフォルトで」new MyClass<Derived>()は に割り当てられませんnew MyClass<Base>()。しかし、インターフェイスの共分散を使用してトリックを実行できます。

class Person { }

class Manager : Person { }

interface IPaymentCalculator<out T> where T : Person
{
}

class PaymentCalculator<T> : IPaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}

class Calculators : List<IPaymentCalculator<Person>>
{
    public Calculators()
    {
        this.Add(new PaymentCalculator<Person>());
        this.Add(new PaymentCalculator<Manager>());     // this doesn't work

        PassCalculator(new PaymentCalculator<Person>());
        PassCalculator(new PaymentCalculator<Manager>());   // this doesn't work
    }

    public void PassCalculator(IPaymentCalculator<Person> x)
    { }
}

これはコンパイルして動作します。

于 2012-09-07T18:24:14.120 に答える
1

Managerから継承していますがPerson、から継承PaymentCalculator<Manager>していませんPaymentCalculator<Person>contravariantの場合PaymentCalculator<T>は機能しますが、.NET ではクラスを反変にすることはできません (インターフェイスとデリゲートのみが反変になる可能性があります)。

問題の可能な解決策は、次のように反変のインターフェイスを宣言することです。

interface IPaymentCalculator<in T> // "in" means contravariant
{
    double Calculate(T person);
}

Makeは次のインターフェイスをPaymentCalculator<T>実装します。IPaymentCalculator<T>

class PaymentCalculator<T> : IPaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}

そして、Calculatorsクラスを継承させますList<IPaymentCalculator<Person>>

class Calculators : List<IPaymentCalculator<Person>>

これらの変更により、期待どおりに動作するはずです。

于 2012-09-07T18:26:07.630 に答える