399

匿名型にインターフェースを実装させることは可能ですか。作業したいコードがありますが、その方法がわかりません。

私は、ノーと言うか、インターフェースを実装するクラスを作成して、その新しいインスタンスを作成するという、いくつかの答えを得ました。これは実際には理想的ではありませんが、これを単純にするインターフェースの上に薄い動的クラスを作成するためのメカニズムがあるかどうか疑問に思います。

public interface DummyInterface
{
    string A { get; }
    string B { get; }
}

public class DummySource
{
    public string A { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class Test
{
    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values);

    }

    public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

記事を見つけました動的インターフェースの折り返しそれは1つのアプローチを説明します。これはこれを行うための最善の方法ですか?


  • 少し話題を外れていますが、これはJavaで行うことができますか?私はそれがどこかで行われているのを見たと確信しています... - Mark McDonald
  • C4H5As:これも以前にも見たことがあると思います。たぶんVB.Netはそれをすることができますか?あるいは、私はJavaを考えているだけかもしれません。 - Josh Mouch
  • リンクが古くなっているようですが、これはおそらく適切な選択肢ですliensberger.it/web/blog/?p=298。 - Phil Cooper
  • Javaで@ C4H5Asと呼ばれる匿名クラス - Jupiter
  • 許可されている場合、次のqは次のようになります。匿名クラスに2つのインターフェースを実装する:P要求は終わらない。 - nawfal

7 답변


313

いいえ、匿名型はインターフェースを実装できません。からC#プログラミングガイド

匿名型は、1つ以上の公開読み取り専用プロパティで構成されるクラス型です。メソッドやイベントなど、他の種類のクラスメンバーは許可されません。匿名型は、オブジェクト以外のインターフェイスまたは型にはキャストできません。


  • +1 - 無名型の使用は通常、ラムダ式とLINQ式に限定されるべきです。データ「何かをする」必要がある発信者に公開されています。オブジェクトに関しては、具象クラスを実装することはとても良い考えです。 - Mark
  • @ Mark:DTOとして匿名型を使うのも好きです。いくつかのシナリオでは自動マッピングがうまく機能します。 - boj
  • とにかくこのものを持っているといいでしょう。コードの読みやすさについて話しているのであれば、ラムダ式は通常うまくいく方法ではありません。 RADについて話しているのであれば、すべてJavaに似た匿名インターフェースの実装に取り掛かります。ところで、いくつかのケースでは、その機能はデリゲートよりも強力です。 - Arsen Zahray
  • @ArsenZahray:ラムダ式をうまく使用すると、実際にコードの読みやすさが向上します。これらは、機能チェーンで使用されると特に強力であり、ローカル変数の必要性を減らすか排除することができます。 - Roy Tinker
  • @ DmitryPavlov、それは驚くほど貴重でした。通行人:ここに要約版です。 - kdbanman

82

これは2年前の質問かもしれませんが、スレッド内の答えはすべて十分に真実ですが、実際にそれを伝えたいという衝動には耐えられません。可能です匿名クラスにインターフェースを実装させるには、そこに到達するために少し創造的な不正行為が必要です。

2008年に私は当時の雇用者のためにカスタムLINQプロバイダを書いていました、そしてある時点で私は他の匿名クラスから "私"の匿名クラスを伝えることができる必要がありました。それら。私たちがそれを解決した方法はアスペクトを使うことでしたポストシャープ)、ILで直接インタフェース実装を追加するために。だから、実際には、無名クラスにインターフェースを実装させることは可能ですそこにたどり着くには、規則を少し曲げるだけでいいのです。


  • これはまさに私が積極的に避けているような行動です。別のマシンでコンパイルすると、全体がうまくいきます。 - Gusdor
  • 私はルール部分を曲げるのが好きです;) - Beatles1692
  • このケースでは、@Gusdorがビルドを完全に制御し、常に専用のマシンで実行されていました。また、PostSharpを使用していて、そのフレームワーク内で行っていたことは完全に合法的であるため、使用しているビルドサーバーにPostSharpがインストールされていることを確認する限り、実際にはうまくいきません。 - Mia Clarke
  • @Gusdor他のプログラマーにとって大きな困難もなくプロジェクトを手に入れてコンパイルするのは簡単なはずですが、それは別の問題で、ポストシャープのようなツールやフレームワークを完全に避けることなく別々に取り組むことができます。あなたがするのと同じ議論は、VS自体に対しても、C#仕様の一部ではない他のあらゆる非標準のMSフレームワークに対しても行うことができます。あなたはそれらのものを必要とするか、そうでなければそれは "ポップ"になります。これはIMOの問題ではありません。問題は、ビルドが非常に複雑になり、それらすべてを正しく機能させることが困難になる場合です。 - AaronLS
  • @ZainRizviいいえ、できませんでした。私の知る限りでは、まだ本番中です。そのとき心配されたことは私には奇妙に思えました、そして今私にはせいぜい恣意的です。基本的には「フレームワークを使用しないでください、問題は解決します」と言っていました。彼らはそうしなかった、何もポップにはならなかった、そして私は驚いていない。 - Mia Clarke

41

匿名型をインターフェースにキャストすることは私がしばらく望んでいたことですが、残念ながら現在の実装はあなたにそのインターフェースの実装を強いるものです。

それを回避する最善の解決策は、実装を作成する何らかのタイプの動的プロキシを用意することです。優れたLinFuプロジェクトあなたは交換することができます

select new
{
  A = value.A,
  B = value.C + "_" + value.D
};

 select new DynamicObject(new
 {
   A = value.A,
   B = value.C + "_" + value.D
 }).CreateDuck<DummyInterface>();


  • 即興インターフェイスプロジェクト.NET 4.0ではDLRを使ってこれを行い、Linfuよりも軽量です。 - jbtule
  • ですDynamicObjectLinFuタイプ?System.Dynamic.DynamicObject保護されたコンストラクタのみを持ちます(少なくとも.NET 4.5では)。 - jdmcnair
  • はい。私はLinFuの実装を参照していましたDynamicObjectこれはDLRバージョンより前のものです。 - Arne Claassen

12

いいえ。匿名型は、いくつかのプロパティを持つ以外は何もできません。あなたはあなた自身のタイプを作成する必要があるでしょう。リンクされた記事は詳しく読みませんでしたが、Reflection.Emitを使用して新しい型をその場で作成しているようです。議論を物事に限定した場合C#自体の中にあなたが望むことをすることはできません。


  • そして注意することが重要:プロパティも同様に関数やボイド(アクション)を含めることができます:あなたが参照することはできませんが選択新しい{... MyFunction =新しい関数<文字列、ブール>(s => value.A == s)}作品関数の新しいプロパティに追加します(「value.A」の代わりに「A」を使用することはできません)。 - cfeduke
  • まあ、たまたま代理人になるだけの財産ではないでしょうか。実際には方法ではありません。 - Marc Gravell
  • 実行時に型を作成するためにReflection.Emitを使用しましたが、今度は実行時コストを回避するためにAOPソリューションを使用することをお勧めします。 - Norman H

12

匿名型は動的プロキシを介してインタフェースを実装できます。

拡張メソッドを書いたGitHubそしてブログ記事http://wblo.gs/feEこのシナリオをサポートするために。

このメソッドは次のように使用できます。

class Program
{
    static void Main(string[] args)
    {
        var developer = new { Name = "Jason Bowers" };

        PrintDeveloperName(developer.DuckCast<IDeveloper>());

        Console.ReadKey();
    }

    private static void PrintDeveloperName(IDeveloper developer)
    {
        Console.WriteLine(developer.Name);
    }
}

public interface IDeveloper
{
    string Name { get; }
}


11

最善の解決策は、無名クラスを使用しないことです。

public class Test
{
    class DummyInterfaceImplementor : IDummyInterface
    {
        public string A { get; set; }
        public string B { get; set; }
    }

    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new DummyInterfaceImplementor()
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());

    }

    public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

クエリの結果をインタフェースの型にキャストする必要があることに注意してください。もっと良い方法があるかもしれませんが、見つけることができませんでした。


  • あなたが使用することができますvalues.OfType<IDummyInterface>()キャストではなく実際にその型にキャストできるコレクション内のオブジェクトのみを返します。それはすべてあなたが望むものに依存します。 - Kristoffer L

7

具体的に尋ねられた質問に対する答えはノーです。しかし、あなたはモックフレームワークを見てきましたか?私はMOQを使用していますが、そこには何百万ものものがあり、それらを使用すると(部分的にまたは完全に)インターフェースをインラインで実装できます。例えば。

public void ThisWillWork()
{
    var source = new DummySource[0];
    var mock = new Mock<DummyInterface>();

    mock.SetupProperty(m => m.A, source.Select(s => s.A));
    mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));

    DoSomethingWithDummyInterface(mock.Object);
}

リンクされた質問


最近の質問