c# - 肩書き - 部長 英語表記




一般的なパラメータの組み合わせを利用しようとしています (4)

@ Evkの回答をサポートするためだけのものです。 この例を見てください。

class Program
{
    static void Main(string[] args)
    {
        MyClass<SomeSomething, AnOperation<Something>> foo = 
        new MyClass<SomeSomething, AnOperation<Something>>(); 
        // AnOperation<SomeSomething> will cause a compile error.

        var bar = foo.GetAnOperationOfSomething();

        Console.WriteLine(bar != null);

        Console.Read();
    }
}

class MyClass<T, U>
    where T : Something
    where U : AnOperation<Something>
{
    public U GetAnOperationOfSomething()
    {
        U anOperation = Activator.CreateInstance<U>();

        return anOperation;
    }
}

public class Something
{
}

public class AnOperation<T>
    where T : Something
{
}

public class SomeSomething : Something
{
}

私は一見矛盾するエラーになっているので、これは紛らわしいです。

私は総称を使い、 TSomethingに拘束し、次にUAnOperation<Something>拘束します。

オブジェクトAnOperation<Something>AnOperation<Something> U型と見なされると思います。 しかし、私はエラーを受けています:

Cannot implicitly convert type 'ConsoleApp1.AnOperation<T>' to 'U'

それは変だ。 さて、私は明示的にそれをUにキャストしようとしました、そして私はこのエラーを得ました:

Cannot convert type 'ConsoleApp1.AnOperation<T>' to 'U'これもCast is redundantあることを示していCast is redundant

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    class MyClass<T, U>
        where T : Something
        where U : AnOperation<Something>
    {
        public U GetAnOperationOfSomething()
        {
            AnOperation<T> anOperation = new AnOperation<T>();

            return anOperation; // Cannot implicitly convert type 'ConsoleApp1.AnOperation<T>' to 'U'

            // return (U)anOperation; // Cannot convert type 'ConsoleApp1.AnOperation<T>' to 'U' also Cast is redundant
        }
    }

    public class Something
    {
    }

    public class AnOperation<T>
        where T : Something
    {
    }

}

ここで何が起きているの?

編集:私は実際の問題の回避策を探しているのではなく、言語レベルでの問題は何かを理解しようとしています。


AnOperationクラスからIAnOperationインターフェースに切り替えると、驚くほどコンパイルされます。

class MyClass<T, U>
    where T : Something
    where U : IAnOperation<Something>
{
    public U GetAnOperationOfSomething()
    {
        IAnOperation<T> anOperation = GenAnOperation();
        return (U)anOperation;
    }

    private IAnOperation<T> GenAnOperation()
    {
        throw new NotImplementedException();
    }
}

public class Something
{ }

public interface IAnOperation<T>
    where T : Something
{ }

あなたのクラスのTSomething継承したクラスです。 UAnOperation<Something>継承したクラスです。 このような子クラスがあるとします。

public class ChildOperation<T> : AnOperation<T> {}

今、あなたのUChildOperation<Something>かもしれません、そしてあなたは子クラスのインスタンス( ChildOperation<Something> U )として親クラス( AnOperation<T> )のインスタンスを返すことはできません。 AnOperation<Something>AnOperation<ChildSomething>暗黙的に変換することはできないため、 Tが本当にChildSomethingである場合にも問題が発生する可能性があります。 長い話を短くする - AnOperation<T>は必ずしもあなたのU型に変換できるわけではないので、コンパイラは正しいです。


あなたはあなたの制約でそれをほぼ正しくしました、しかしそれほどではありません。 あなたが定義する

 where U : AnOperation<Something>

しかし、あなたは作成します

AnOperation<T> anOperation = new AnOperation<T>()

それは同じことではありません。 制約をに変更すると...

 where U : AnOperation<T>

...きっと大丈夫だよ。

別の問題は、すべてのUAnOperation<T>に対して、すべてのAnOperation<T>Uです。 宣言すると…

public U GetAnOperationOfSomething()

...あなたはメソッドが返すものがUという保証をしています。 AnOperation<T>はその保証を満たすことができません。

あなたはこれをUへの型キャストで解決しています。 すべてのUAnOperation<T>なければならないため、これは汎用クラスの目的に反します。そうしないと、ランタイム例外が発生します。 それは型パラメータU全体を不要にします。 あなたが実際にやりたいことはU作ることです。 これにはnew()制約を使用できます。

class MyClass<T, U>
    where T : Something
    where U : AnOperation<T>, new()
{
    public U GetAnOperationOfSomething()
    {
        U anOperation = new U();
        //...
        return anOperation;
    }
}

new()制約は、 Uがパブリックデフォルトコンストラクタを持つことを保証します。これを呼び出すことができます。





generics