10

Eric Lippert は、彼のブログ投稿 ( http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx ) で、なぜ制約が適用されないのかを説明しています。これは、型の制約を変更するだけではメソッドをオーバーロードできないことを考えると理にかなっています。ただし、タイプを指定することなく、2 つのジェネリック型を使用してオブジェクトをインスタンス化する方法を見つけたいと思います。

与えられたタイプ:

public interface I<T>
{
    Other<T> CreateOther();
}

public class C : I<string>
{
    public Other<string> CreateOther()
    {
        return new Other<string>();
    }
}

public class Other<T>
{
}

そして工場:

public static class Factory1
{
    public static Tuple<T, Other<T1>> Create<T, T1>(T o) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

次の目的のコードはコンパイルされません。

    public void WontCompile()
    {
        C c = new C();
        var v = Factory1.Create(c); // won't compile
    }

エラー メッセージは「エラー CS0411: メソッド 'yo.Factory1.Create(T)' の型引数を使用法から推測できません。型引数を明示的に指定してください。」であり、これは Eric がブログで述べたことと一致しています。役職。

したがって、エラー メッセージが示すように、ジェネリック型引数を明示的に指定するだけです。

    public void SpecifyAllTypes()
    {
        C c = new C();
        var v = Factory1.Create<C, string>(c); // type is Tuple<C, Other<string>>
    }

型引数を指定したくなく、型 C を保持する必要がない場合は、次のファクトリを使用できます。

public static class Factory2
{
    public static Tuple<I<T1>, Other<T1>> CreateUntyped<T1>(I<T1> o)
    {
        return new Tuple<I<T1>, Other<T1>>(o, o.CreateOther());
    }
}

次に指定します。

    public void Untyped()
    {
        C c = new C();
        var v = Factory2.CreateUntyped(c); // type is Tuple<I<string>, Other<string>>
    }

ただし、返されるオブジェクトに型 C を保持し、型を指定したくありません。

4

1 に答える 1

5

この問題の解決策を思いつきましたが、2 段階のファクトリ コールで型 C のオブジェクトが 2 回使用される回避策のようです。

これを行うには、次のファクトリが使用されます。

public static class Factory3
{
    public static Factory<T1> CreateFactory<T1>(I<T1> o)
    {
        return new Factory<T1>();
    }
}

public class Factory<T1>
{
    public Tuple<T, Other<T1>> Create<T>(T o) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

これは次のように使用できます。

    public void Inferred()
    {
        C c = new C();
        var v = Factory3.CreateFactory(c).Create(c); // type is Tuple<C, Other<string>>
    }

c が 2 回使用されているため、これは奇妙に感じます。初めて使用されるときは、基本型引数を推測するために使用されるだけなので、実際には破棄されます。

オブジェクトを 2 回使用する必要がなく、型を指定する必要がない、この問題に対するより良い解決策はありますか?

編集:オブジェクトは 2 回使用する必要がありますが、2 番目のファクトリ クラスは必要ないことに気付きました。むしろ、次のように両方のパラメータを同じファクトリ メソッドで使用できます。

public class Factory
{
    public Tuple<T, Other<T1>> Create<T, T1>(T o, I<T1> o2) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

これは次のように使用されます。

public void Inferred()
{
    C c = new C();
    var v = Factory.Create(c, c); // type is Tuple<C, Other<string>>
}

これはまだ理想的ではありませんが、2 番目のファクトリ クラスを作成するよりはましです。少なくとも XMLDoc コメントを使用して、両方のパラメーターが同じオブジェクトであることを示すことができます。繰り返しになりますが、1 つのパラメーター (o2この場合) は、 の制約された型を推測するためにのみ使用されTます。

于 2012-12-22T15:25:39.497 に答える