我有一个返回匿名类型的查询,查询在方法中。你是怎么写的:
public "TheAnonymousType" TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return "TheAnonymousType";
}
}
答案 0 :(得分:78)
你不能。
您只能返回object
或对象容器,例如IEnumerable<object>
,IList<object>
等
答案 1 :(得分:36)
您可以返回dynamic
,它将为您提供匿名类型的运行时检查版本,但仅限于.NET 4+
答案 2 :(得分:25)
您无法返回匿名类型。你能创建一个可以返回的模型吗?否则,您必须使用object
。
Here is an article written by Jon Skeet on the subject
文章中的代码:
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);
}
}
Or, here is another similar article
或者,正如其他人正在发表评论一样,您可以使用dynamic
答案 3 :(得分:17)
当需要返回时,您可以使用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
答案 4 :(得分:17)
在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包。
答案 5 :(得分:9)
C#编译器是一个两阶段编译器。在第一阶段,它只检查名称空间,类层次结构,方法签名等。方法体仅在第二阶段编译。
在编译方法体之前,不会确定匿名类型。
因此编译器无法在第一阶段确定方法的返回类型。
这就是匿名类型不能用作返回类型的原因。
正如其他人所建议的那样,如果您使用.net 4.0或grater,则可以使用Dynamic
。
如果我是你,我可能会创建一个类型并从该方法返回该类型。这样,对于维护代码且更具可读性的未来程序员来说,这很容易。
答案 6 :(得分:8)
三个选项:
选项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
}
}
您将能够将其作为动态对象进行迭代并直接访问其属性
答案 7 :(得分:2)
在这种情况下,您可以返回对象列表。
public List<object> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB ;
}
}
答案 8 :(得分:2)
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
返回,但它仍然不会让您看到匿名类型变量中的内容。
在我尝试重构某些代码之前,我遇到过类似的问题,你可以在这里查看:Refactoring and creating separate methods
答案 9 :(得分:2)
使用 C#7.0 ,我们仍然无法返回匿名类型,但是我们支持元组类型,因此我们可以返回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))
答案 10 :(得分:2)
有反思。
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
答案 11 :(得分:0)
您只能使用动态关键字
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等......
答案 12 :(得分:0)
另一个选项可能是使用自动映射器:只要公共属性匹配,您就可以从匿名返回的对象转换为任何类型。 关键点是,返回对象使用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; }
}
}
}
答案 13 :(得分:0)
现在特别具有局部功能,但是您始终可以通过传递一个使该匿名类型成为代表的委托来实现。
因此,如果您的目标是在相同的源上运行不同的逻辑,并能够将结果合并到一个列表中。不知道要达到既定目标缺少什么细微差别,但是只要您返回一个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);
}
答案 14 :(得分:0)
实际上有可能在特定用例中从方法返回匿名类型。让我们看看!
使用C#7,可以从方法中返回匿名类型,尽管它带有一些约束。我们将使用一种名为local function的新语言功能以及一个间接技巧(另一层间接技术可以解决任何编程难题,对吧?)。
这是我最近发现的一个用例。从AppSettings
加载所有配置值后,我想记录所有配置值。为什么?因为围绕丢失的值(恢复为默认值)存在一些逻辑,因此需要进行一些解析等等。应用逻辑后记录值的一种简单方法是将所有值放在一个类中,并将其序列化到日志文件(使用log4net)。我还想封装处理设置的复杂逻辑,并将其与我需要对它们进行的处理分开。所有这些都没有创建仅存在一次使用的命名类!
让我们看看如何使用创建匿名类型的本地函数来解决这个问题。
public static HttpClient CreateHttpClient()
{
// I deal with configuration values in this slightly convoluted way.
// The benefit is encapsulation of logic and we do not need to
// create a class, as we can use an anonymous class.
// The result resembles an expression statement that
// returns a value (similar to expressions in F#)
var config = Invoke(() =>
{
// slightly complex logic with default value
// in case of missing configuration value
// (this is what I want to encapsulate)
int? acquireTokenTimeoutSeconds = null;
if (int.TryParse(ConfigurationManager.AppSettings["AcquireTokenTimeoutSeconds"], out int i))
{
acquireTokenTimeoutSeconds = i;
}
// more complex logic surrounding configuration values ...
// construct the aggregate configuration class as an anonymous type!
var c = new
{
AcquireTokenTimeoutSeconds =
acquireTokenTimeoutSeconds ?? DefaultAcquireTokenTimeoutSeconds,
// ... more properties
};
// log the whole object for monitoring purposes
// (this is also a reason I want encapsulation)
Log.InfoFormat("Config={0}", c);
return c;
});
// use this configuration in any way necessary...
// the rest of the method concerns only the factory,
// i.e. creating the HttpClient with whatever configuration
// in my case this:
return new HttpClient(...);
// local function that enables the above expression
T Invoke<T>(Func<T> func) => func.Invoke();
}
我已经成功构造了一个匿名类,并且还封装了处理复杂设置管理的逻辑,所有这些都在CreateHttpClient
内部和其自身的“表达式”中。这可能不是OP想要的,但它是一种轻量级的匿名类型的方法,当前在现代C#中是可能的。