匿名型を返すクエリがあり、そのクエリはメソッド内にあります。これをどのように書きますか:
public "TheAnonymousType" TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return "TheAnonymousType";
}
}
できません。
object
、またはオブジェクトのコンテナのみを返すことができます。 IEnumerable<object>
、IList<object>
など.
dynamic
を返すことができます。これは、.NET 4+でのみ、匿名型のランタイムチェックバージョンを提供します。
匿名型を返すことはできません。返せるモデルを作成できますか?それ以外の場合は、object
を使用する必要があります。
記事のコード:
using System;
static class GrottyHacks
{
internal static T Cast<T>(object target, T example)
{
return (T) target;
}
}
class CheesecakeFactory
{
static object CreateCheesecake()
{
return new { Fruit="Strawberry", Topping="Chocolate" };
}
static void Main()
{
object weaklyTyped = CreateCheesecake();
var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
new { Fruit="", Topping="" });
Console.WriteLine("Cheesecake: {0} ({1})",
stronglyTyped.Fruit, stronglyTyped.Topping);
}
}
または、他の人がコメントしているように、dynamic
を使用できます
C#7では、タプルを使用してこれを実現できます。
public List<(int SomeVariable, string AnotherVariable)> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB
.Select(s => (
SomeVariable = s.SomeVariable,
AnotherVariable = s.AnotherVariable))
.ToList();
}
}
ただし、System.ValueTuple
nugetパッケージをインストールする必要がある場合があります。
返す必要がある場合、匿名型の代わりにTupleクラスを使用できます。
注:タプルには最大8つのパラメーターを指定できます。
return Tuple.Create(variable1, variable2);
または、元の投稿の例:
public List<Tuple<SomeType, AnotherType>> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select Tuple.Create(..., ...)
).ToList();
return TheQueryFromDB.ToList();
}
}
http://msdn.Microsoft.com/en-us/library/system.Tuple(v = vs.110).aspx
C#コンパイラは2フェーズコンパイラです。最初のフェーズでは、名前空間、クラス階層、メソッドシグネチャなどをチェックするだけです。メソッド本体は、2番目のフェーズでのみコンパイルされます。
匿名型は、メソッド本体がコンパイルされるまで決定されません。
そのため、コンパイラには、最初のフェーズでメソッドの戻り値の型を決定する方法がありません。
これが、匿名型を戻り型として使用できない理由です。
.net 4.0以降を使用している場合は他の人が示唆しているように、Dynamic
を使用できます。
もし私があなただったら、おそらく型を作成し、メソッドからその型を返すでしょう。そうすれば、コードを維持し、読みやすくする将来のプログラマーにとって簡単です。
3つのオプション:
オプション1:
public class TheRepresentativeType {
public ... SomeVariable {get;set;}
public ... AnotherVariable {get;set;}
}
public IEnumerable<TheRepresentativeType> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB;
}
}
オプション2:
public IEnumerable TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB;
}
}
オブジェクトとしてそれを繰り返すことができます
オプション3:
public IEnumerable<dynamic> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB; //You may need to call .Cast<dynamic>(), but I'm not sure
}
}
そして、動的オブジェクトとしてそれを繰り返し、それらのプロパティに直接アクセスできるようになります
この場合、オブジェクトのリストを返すことができます。
public List<object> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB ;
}
}
反射あり。
public object tst() {
var a = new {
prop1 = "test1",
prop2 = "test2"
};
return a;
}
public string tst2(object anonymousObject, string propName) {
return anonymousObject.GetType().GetProperties()
.Where(w => w.Name == propName)
.Select(s => s.GetValue(anonymousObject))
.FirstOrDefault().ToString();
}
サンプル:
object a = tst();
var val = tst2(a, "prop2");
出力:
test2
public List<SomeClass> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new SomeClass{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB.ToList();
}
}
public class SomeClass{
public string SomeVariable{get;set}
public string AnotherVariable{get;set;}
}
独自のクラスを作成してそれをクエリすることは、私が知っている最良のソリューションです。方法。以前は、IQueryable
またはIEnumerable
としてそれらを返しましたが、それでも匿名型変数の中にあるものを見ることができません。
以前、コードをリファクタリングしようとしていたときにこのようなことが発生しました。ここで確認できます。 リファクタリングと個別のメソッドの作成
C#7.を使用しても、匿名型を返すことはできませんが、タプル型をサポートしているため、Tuple
(System.ValueTuple<T1,T2>
この場合)。
必要なコードの最短バージョンは次のようになります。
public List<(int SomeVariable, object AnotherVariable)> TheMethod()
{
...
return (from data in TheDC.Data
select (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject)
).ToList();
}
または、流れるようなLinq構文を使用します。
return TheDC.Data
.Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))
.ToList();
C#7.1を使用すると、タプルのプロパティ名を省略することができ、匿名型で機能するようにタプルの初期化から推測されます。
select (data.SomeInt, data.SomeObject)
// or
Select(data => (data.SomeInt, data.SomeObject))
現在は特にローカル関数を使用していますが、匿名型を作成するデリゲートを渡すことでいつでも実行できます。
そのため、同じソースで異なるロジックを実行し、結果を単一のリストに結合できるようにすることが目標だった場合。指定された目標を達成するためにこれがどのようなニュアンスに欠けているかはわかりませんが、T
を返し、デリゲートを渡してT
を作成する限り、関数から匿名型を返すことができます。
// returning an anonymous type
// look mom no casting
void LookMyChildReturnsAnAnonICanConsume()
{
// if C# had first class functions you could do
// var anonyFunc = (name:string,id:int) => new {Name=name,Id=id};
var items = new[] { new { Item1 = "hello", Item2 = 3 } };
var itemsProjection =items.Select(x => SomeLogic(x.Item1, x.Item2, (y, i) => new { Word = y, Count = i} ));
// same projection = same type
var otherSourceProjection = SomeOtherSource((y,i) => new {Word=y,Count=i});
var q =
from anony1 in itemsProjection
join anony2 in otherSourceProjection
on anony1.Word equals anony2.Word
select new {anony1.Word,Source1Count=anony1.Count,Source2Count=anony2.Count};
var togetherForever = itemsProjection.Concat(otherSourceProjection).ToList();
}
T SomeLogic<T>(string item1, int item2, Func<string,int,T> f){
return f(item1,item2);
}
IEnumerable<T> SomeOtherSource<T>(Func<string,int,T> f){
var dbValues = new []{Tuple.Create("hello",1), Tuple.Create("bye",2)};
foreach(var x in dbValues)
yield return f(x.Item1,x.Item2);
}
別のオプションは、オートマッパーを使用することです。パブリックプロパティが一致する限り、返された匿名オブジェクトから任意の型に変換します。キーポイントは、オブジェクトを返す、linqとautommaperを使用することです。 (または、シリアル化されたjsonなどを返す同様のアイデアを使用するか、リフレクションを使用します。)
using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var data = GetData();
var firts = data.First();
var info = firts.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).First(p => p.Name == "Name");
var value = info.GetValue(firts);
Assert.AreEqual(value, "One");
}
[TestMethod]
public void TestMethod2()
{
var data = GetData();
var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var mapper = config.CreateMapper();
var users = data.Select(mapper.Map<User>).ToArray();
var firts = users.First();
Assert.AreEqual(firts.Name, "One");
}
[TestMethod]
public void TestMethod3()
{
var data = GetJData();
var users = JsonConvert.DeserializeObject<User[]>(data);
var firts = users.First();
Assert.AreEqual(firts.Name, "One");
}
private object[] GetData()
{
return new[] { new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } };
}
private string GetJData()
{
return JsonConvert.SerializeObject(new []{ new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } }, Formatting.None);
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
}
}
動的キーワードのみを使用できますが、
dynamic obj = GetAnonymousType();
Console.WriteLine(obj.Name);
Console.WriteLine(obj.LastName);
Console.WriteLine(obj.Age);
public static dynamic GetAnonymousType()
{
return new { Name = "John", LastName = "Smith", Age=42};
}
しかし、動的型キーワードを使用すると、コンパイル時の安全性が失われます。IDE IntelliSenseなど...