7

既存のジェネリッククラスがあります

public class Foo<T>
{
    private T _item;
    public Foo(T item){ _item = item;}
}

Tの特定のプロパティを返すメソッドを作成する必要があり
ます。ここに2つの解決策があります。

  1. インターフェイスの作成:

    public const string TestVar = "bar";
    public interface INamable { string Name { get; } }
    public class Bar : INamable
    {
        public string Name { get { return TestVar; } }
    }
    
    public class Foo<T> where T : INamable
    {
        private T _item;
        public Foo(T item) { _item = item; }
        public string GetName() { return this._item.Name; }
    }
    
    [TestMethod()]
    public void TestInterface()
    {
        var bar = new Bar();
        var foo = new Foo<Bar>(bar);
        Assert.AreEqual(TestVar, foo.GetName());
    }
    
  2. Funcを渡す:

    public const string TestVar = "bar";
    public class Bar
    {
        public string Name { get { return TestVar; } }
    }
    
    public class Foo<T>
    {
        private T _item;
        private Func<T, string> _funcName;
        public Foo(T item, Func<T, string> funcName) { _item = item; _funcName = funcName; }
        public string GetName() { return _funcName.Invoke(_item); }
    }
    
    [TestMethod()]
    public void TestFunc()
    {
        var bar = new Bar();
        var foo = new Foo<Bar>(bar, b => b.Name);
        Assert.AreEqual(TestVar, foo.GetName());
    }
    

インターフェイスを作成する必要がなく、怠惰なので、2番目のソリューションを使用します。すでにfooコンストラクターの呼び出しに1つのパラメーターを追加する必要があります。

さらに、Fooクラスは今でもあらゆる種類のクラスで使用できるので、私はこの方法を好みます。

しかし、それがFuncを使用する良い方法かどうかはわかりませんか?それでも素晴らしくてしっかりしていますか?Funcを使うのはこれが初めてなので、自分に問いかけています。

数ヶ月前、私は古典的なインターフェースを備えた最初のソリューションを使用しました...

4

4 に答える 4

3

最初の解決策(つまり、Funcがない)ははるかに簡単です。庭のさまざまなプロパティアクセサーを実装するためにFuncオブジェクトを呼び出す必要はまったくありません。

于 2012-07-30T15:23:04.250 に答える
3

インターフェイスが1つのメソッドだけで終わる場合は、代わりに使用ActionまたはFunc委任するのが完全に有効です。それははるかにきれいな私見です。

ただし、書く必要はありませんInvoke。かっこで呼び出すだけです。_funcName(_item)

于 2012-07-30T15:38:44.160 に答える
3

コメントから私はあまり明確ではないことに気づいたので、私は私の答えを言い換えています。

それはあなたのコードの意図とあなたのクラスに名前を付ける責任がある人に依存します(クライアントはクラスに名前を付ける方法を知って指定する必要がありますが、クラスには本質的に名前が必要です)。@ Scorpi0の例を少し変更しているので、Fooは名前を返すだけでなく、実際にその名前で何かを実行します(挨拶します)。

例1(インターフェース)

interface INamable { string Name { get; } }

class AThingWithAName : INamable 
{
    public string Name {get {return "thing";}}
}

class AnotherThingWithAName : INamable 
{
    public string Name {get {return "different thing";}}
}

class Foo<T> where T : INamable
{
    public string Greet(T item) {return "hi " + item;}
}

ここで物事はFooに関係なく名前を持っています。Fooは、名前がある限り、物事に挨拶する方法を知っています(これは、INamableインターフェイスを実装することによる契約によって保証されています)。ここでは、Fooが名前のあるものでのみ機能し、他の何かに挨拶しようとすることは、コンパイラーによってキャッチされたタイプエラーであることを保証したいと思います。

また、各クラスでNameの具体的な実装をカプセル化していることに注意してください。名前は、そのクラスのプライベート状態に依存する可能性があります。

例2(ファンク)

class AThing {}
class AnotherUnrelatedThing {}

class Foo<T>
{
    public string Greet(T item, Func<T, string> namingFunction) 
    {
        return "hi " + namingFunction(item);
    }
}

ここではFooに重点が置かれています。物事には必ずしも名前がありません。何でも挨拶できるクラスFooを作りたいです。それはどのようにそれをしますか?さて、どのタイプでも、そのタイプに名前を付けることができる関数を渡すのは呼び出し元の責任です。この場合、Tが自分の名前を知っているという保証を要求していないだけでなく、名前を付ける方法を知っている限り、任意のタイプに挨拶できるようにFooを構築しています。たとえば、これは機能します。

var foo = new Foo<int>();
var res=foo.Greet(2, n=>n.ToString());

その柔軟性と引き換えに、カプセル化をあきらめています。これで、Nameはクラスの実装責任ではなくなりました。私たち(呼び出し元)は、Fooに、使用する各クラスに名前を付ける方法を指示しています。

したがって、表現したい内容に応じて、Fooに関係なく名前を持つオブジェクトの階層がある場合は、どちらか一方を選択できます。

于 2012-07-30T15:38:57.837 に答える
2

vb.netコンパイラとC#コンパイラの両方に非常に使いやすい機能が含まれているため、多くの場合、デリゲートは実装者にとってより便利になります。インターフェイスは、デリゲートが実行できないいくつかのことを実行でき(たとえば、オープンジェネリックメソッドファミリを含む)、場合によっては、デリゲートよりも効率的である可能性があります(インターフェイスを実装するオブジェクトへの参照は、別のインターフェイスタイプを作成せずに、そのインターフェイスタイプとして渡される可能性があるため)それを保持するヒープオブジェクト)。コンパイラがインラインデリゲートの簡単な作成をサポートしているという事実は、単一機能インターフェイスに匹敵する機能を提供していませんが、前者を支持する非常に強力な議論を示しています。

于 2012-07-30T22:28:03.827 に答える