web-dev-qa-db-ja.com

メソッドから匿名型を返す方法はありますか?

私は次のようなメソッドを書くことができないことを知っています:

public var MyMethod()
{
   return new{ Property1 = "test", Property2="test"};
}

それ以外の場合はできます:

public object MyMethod()
{
   return new{ Property1 = "test", Property2="test"}
}

しかし、2番目のオプションを実行したくないのは、そうする場合、リフレクションを使用する必要があるためです。


なぜそれをしたいのですか:

今日、結果としてデータテーブルを返すメソッドがaspxページ内にあり、私は変更することはできません、このDataTableを処理したいプロパティを持つ匿名メソッドに変換しようとしました。それを行うためだけにクラスを作成したくはありませんでした。同じクエリを複数回実行する必要があるので、匿名型を返すメソッドを作成することは良い考えです。

63
Cleiton

System.Objectとして返すことは、メソッドから匿名型を返すonly方法です。残念ながら、匿名型はこの方法での使用を防ぐために特別に設計されているため、これを行う他の方法はありません。

Objectを返すことに関連して、あなたが近くにいることを可能にするいくつかのトリックがあります。この回避策に興味がある場合は、 メソッドから匿名型を返すことができませんか?本当に? をお読みください。

免責事項:私がリンクした記事は回避策を示していますが、それはそれが良いアイデアであることを意味しません。通常の型を作成する方が安全で理解しやすい場合は、このアプローチを使用しないことを強くお勧めします。

64
Andrew Hare

または、.NET 4.0以降でTupleクラスを使用できます。

http://msdn.Microsoft.com/en-us/library/system.Tuple(v = vs.110).aspx

Tuple<string, string> Create()
{
return Tuple.Create("test1", "test2");
} 

その後、次のようなプロパティにアクセスできます。

var result = Create();
result.Item1;
result.Item2;
25
The Light
public object MyMethod() 
{
    return new
    {
         Property1 = "test",
        Property2 = "test"
     };
}

static void Main(..)
{
    dynamic o = MyMethod();  
    var p1 = o.Property1;
    var p2 = o.Property2;
}
18
Nana Kofi

最も簡単な解決策は、クラスを作成し、値をプロパティに押し込んでから返すことです。匿名型があなたの人生を難しくしているなら、あなたはそれらを正しく使用していません。

16
Jagd

別の方法として、C#7以降では ValueTuple を使用できます。 here からの小さな例:

public (int sum, int count) DoStuff(IEnumerable<int> values) 
{
    var res = (sum: 0, count: 0);
    foreach (var value in values) { res.sum += value; res.count++; }
    return res;
}

そして、受信側で:

var result = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {result.Sum}, Count: {result.Count}");

または:

var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {sum}, Count: {count}");
13
baur

これが良いアイデアであるかどうかについての警告にもかかわらず... dynamicはプライベートメソッドに対してはうまく機能するようです。

void Main()
{
    var result = MyMethod();
    Console.WriteLine($"Result: {result.Property1}, {result.Property2}");
}

public dynamic MyMethod()
{
    return new { Property1 = "test1", Property2 = "test2" };
}

この例を LinqPad。 で実行できます。出力されます:

結果:test1、test2

8
controlbox

いいえ、匿名型は、作成されたコンテキストの外部に存在することはできません。その結果、メソッドの戻り値型として使用することはできません。インスタンスをobjectとして返すことができますが、この目的のために独自のコンテナタイプを明示的に作成することをお勧めします。

3
Adam Robinson

アンドリュー・ヘアが正しいと思う、あなたはただ「オブジェクト」を返さなければならないでしょう。編集上のコメントについては、OOコードは「コードの匂い」になる可能性があります。関連する型を返す場合は、返すインターフェイスを定義するか、何らかの基本クラス型を使用することをお勧めします。

3
Andy White

申し訳ありませんが、あなたは本当にそうすることになっていない。リフレクションを使用するか、ジェネリックヘルパーメソッドを作成して型を返すことで、ハッキングすることができますが、そうすることは実際に言語に対して機能します。何が起こっているのかが明確になるように、型を宣言するだけです。

2
mqp

いいえ、匿名クラスのスコープをメソッド外に拡張することはサポートされていません。メソッド以外では、クラスは本当に匿名であり、リフレクションがそのメンバーにアクセスする唯一の方法です。

2
Guffa

可能であれば、制御フローを逆にすることもできます。

    public abstract class SafeAnon<TContext>
    {
        public static Anon<T> Create<T>(Func<T> anonFactory)
        {
            return new Anon<T>(anonFactory());
        }

        public abstract void Fire(TContext context);
        public class Anon<T> : SafeAnon<TContext>
        {
            private readonly T _out;

            public delegate void Delayed(TContext context, T anon);

            public Anon(T @out)
            {
                _out = @out;
            }

            public event Delayed UseMe;
            public override void Fire(TContext context)
            {
                UseMe?.Invoke(context, _out);
            }
        }
    }

    public static SafeAnon<SomeContext> Test()
    {
        var sa = SafeAnon<SomeContext>.Create(() => new { AnonStuff = "asdf123" });

        sa.UseMe += (ctx, anon) =>
        {
            ctx.Stuff.Add(anon.AnonStuff);
        };

        return sa;
    }

    public class SomeContext
    {
        public List<string> Stuff = new List<string>();
    }

その後、他の場所で:

    static void Main()
    {
        var anonWithoutContext = Test();

        var nowTheresMyContext = new SomeContext();
        anonWithoutContext.Fire(nowTheresMyContext);

        Console.WriteLine(nowTheresMyContext.Stuff[0]);

    }
2
sneusse