2

この質問と同様に、複数のインターフェイスを実装するためにメソッド引数を要求するにはどうすればよいですか? メソッド引数にいくつかのインターフェイスを実装したい。

インターフェイスは任意の方法で組み合わせることができ、有効な組み合わせごとにインターフェイスを作成したくありません。

ファイルについて考えてみてください。かもね:

  1. 読み取り可能=>IReadable
  2. 書き込み可能=>IWriteable
  3. アーカイブ=>IArchive
  4. 自動生成=>IGenerated

..。

引数が書き込み可能で生成されたアーカイブである必要があることを表現したい場合は、IWritableGeneratedArchive組み合わせが多すぎて、変更できない既存のクラスで使用したいので、生成したくありません。

擬似コード:

void WriteTo( IWritable + IGenerated + IArchive file)
{
   //...
}
4

5 に答える 5

8

ここで見つけた解決策:複数のインターフェースを実装するためにメソッド引数を要求するにはどうすればよいですか?C#用に調整。

クレジットはマイケルマイヤーズに行きます

internal interface IF1
{
    void M1();
}

internal interface IF2
{
    void M2();
}

internal class ClassImplementingIF1IF2 : IF1, IF2
{

    public void M1()
    {
        throw new NotImplementedException();
    }

    public void M2()
    {
        throw new NotImplementedException();
    }

}

internal static class Test
{

    public static void doIT<T>(T t) where T:IF1,IF2
    {
        t.M1();
        t.M2();
    }

    public static void test()
    {
        var c = new ClassImplementingIF1IF2();
        doIT(c);
    }
}
于 2012-10-25T13:11:53.913 に答える
3

おそらく一般的な+制約?

void WriteTo<T>( T file) where T : IWritable,IGenerated,IArchive
{
   //...
}
于 2012-10-25T13:19:40.657 に答える
2

一般的な制約を使用します。

void WriteTo<T>(T file) where T: IWritable, IGenerated, IArchive
{
   //...
}

タイプパラメータの制約(C#プログラミングガイド)を参照してください。

于 2012-10-25T13:20:03.327 に答える
0

組み合わせが多すぎるため、IWritableGeneratedArchiveを生成したくない

組み合わせが多すぎるのはどうしてですか?潜在的な組み合わせの数に関係なく、メソッドパラメータとして実際に使用するものの組み合わせインターフェイスを作成するだけで済み、その時点ですべてを書き出すことになります。言い換えれば、それは実際にはそれほど多くの作業ではありません。

変更できない既存のクラスで使用したい。

IWritableGeneratedArchiveタイプは、IArchiveまたはIWritableのみが必要なものに渡すことができます。これは、あなたがすでに持っている他のものでもまだ機能します。


しかし、あなたはすでにこれに反対することを決めており、すでにこのアーキテクチャに多くの投資をしているように見えるので、コードコントラクトを見たことがあるのではないかと思います。彼らはあなたが必要なことをするかもしれないように見えます。

于 2012-10-25T13:19:22.633 に答える
0

このソリューションは、そのような「マルチインターフェイス」オブジェクトを格納することでsupercatのアイデアを取り入れようとします。

私はHolder、オブジェクトの指定されたインターフェイスを公開するクラスにそれらを格納することによってこれを行いました。

Holderオブジェクトは格納でき、期待される引数です。欠点は、Holder最初に作成する必要があり、Holderの型引数の順序が重要になることです。

Holderプラス面としては、動的にsを作成し、もちろん「マルチインターフェイス」オブジェクトを格納することもできます。

holder.Get<T>()メソッド(holder.t1よりも優れ ている)を有効にすると良かったのですが、コンパイルされません。多分誰かがそれを修正する方法を知っていますか?T1制約を追加する必要はないと思いますT2。その逆も同様です。C#ジェネリックに関連するこの継ぎ目は、何かを実装しておらず、解決策を見つけられませんでした。

internal interface IF1
{
    void M1();
}

internal interface IF1_extension : IF1
{
}

internal interface IF2
{
    void M2();
}

internal class ClassImplementingIF1IF2 : IF1_extension, IF2
{

    public void M1()
    {
        throw new NotImplementedException();
    }

    public void M2()
    {
        throw new NotImplementedException();
    }

}

internal interface Getter<T> where T : class
{
    T Get();
}

internal class Holder<T1, T2> //: Getter<T1>, Getter<T2> // not possible since T1 and T2 may be the same => won't compile!
    where T1 : class
    where T2 : class
{
    private Holder(T1 t1, T2 t2)
    {
        Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
        Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
        this.t1 = t1;
        this.t2 = t2;
    }

    public static Holder<T1, T2> CreateFrom<T>(T t) where T : T1, T2
    {
        return new Holder<T1, T2>(t, t);
    }
    public static Holder<T1, T2> CreateDynamicallyFrom(object t)
    {
        return new Holder<T1, T2>(t as T1, t as T2);
    }

    public readonly T1 t1;
    public readonly T2 t2;

    //T1 Getter<T1>.Get()
    //{
    //    return t1;
    //}
    //T2 Getter<T2>.Get()
    //{
    //    return t2;
    //}
}

internal class Holder<T1, T2, T3>  // Holder<T1,T2,T3,T4> etc. are defined in a similar way
    where T1 : class
    where T2 : class
    where T3 : class
{
    private Holder(T1 t1, T2 t2, T3 t3)
    {
        Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
        Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
        Debug.Assert(t3 != null, "Argument is no " + typeof(T3).Name);
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
    }

    public static Holder<T1, T2,T3> CreateFrom<T>(T t) where T : T1, T2, T3
    {
        return new Holder<T1, T2, T3>(t, t, t);
    }
    public static Holder<T1, T2, T3> CreateDynamicallyFrom(object t)
    {
        return new Holder<T1, T2, T3>(t as T1, t as T2, t as T3);
    }

    public readonly T1 t1;
    public readonly T2 t2;
    public readonly T3 t3;

}


internal static class Test
{

    public static void doIt<T>(T t) where T : IF1, IF2
    {
        t.M1();
        t.M2();
    }

    public static void doIt(Holder<IF1, IF2> t) // Interfaces should be mentioned in alpahbetical order since Holder<IF1,IF2> != Holder<IF2,IF1>
    {
        t.t1.M1();
        t.t2.M2();
    }


    public static void doIt_extended<T1, T2>(Holder<T1, T2> t) // handles conversions from Holder<T1,T2> to Holder<T1 or base of T1, T2 or base of T2>
        where T1 : class, IF1
        where T2 : class, IF2
    {
        t.t1.M1();
        t.t2.M2();
    }

    public static void test()
    {
        var c = new ClassImplementingIF1IF2();
        doIt(c);
        var c_holder = Holder<IF1, IF2>.CreateFrom(c);
        doIt(c_holder);

        var another_c_holder = Holder<IF1_extension, IF2>.CreateFrom(c);
        doIt_extended(another_c_holder);


        object diguised_c = c;
        var disguised_c_holder = Holder<IF1, IF2>.CreateDynamicallyFrom(diguised_c);
        doIt(disguised_c_holder);

    }
}
于 2012-10-26T10:40:18.840 に答える