81

我知道我不能写这样的方法:

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

否则我可以这样做:

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

但我不想做第二个选项,因为如果我这样做,我将不得不使用反射。


为什么我想这样做:

今天我在我的 aspx 页面中有一个方法,它返回一个数据表作为结果,我无法更改它,我试图将此 DataTable 转换为具有我想要使用的属性的匿名方法。我不想创建一个类只是为了做到这一点,因为我需要多次执行相同的查询,我认为创建一个返回匿名类型的方法将是一个好主意。

4

11 回答 11

76

将它作为 a返回是从方法返回匿名类型System.Object唯一方法。不幸的是,没有其他方法可以做到这一点,因为匿名类型是专门为防止以这种方式使用而设计的。

有一些技巧可以结合返回一个Object让你接近的技巧。如果您对此解决方法感兴趣,请阅读无法从方法返回匿名类型?真的吗?.

免责声明:即使我链接的文章确实显示了一种解决方法,但这并不意味着这样做是一个好主意。我强烈建议您在创建常规类型更安全且更易于理解时使用这种方法。

于 2009-08-25T17:18:26.323 回答
28

或者,您可以在 .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;
于 2014-02-04T08:16:14.280 回答
24

作为替代方案,从 C# 7 开始,我们可以使用ValueTuple这里的一个小例子:

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}");
于 2018-08-09T11:55:01.313 回答
20
public object MyMethod() 
{
    return new
    {
         Property1 = "test",
        Property2 = "test"
     };
}

static void Main(..)
{
    dynamic o = MyMethod();  
    var p1 = o.Property1;
    var p2 = o.Property2;
}
于 2012-07-12T18:47:03.507 回答
17

最简单的解决方案是创建一个类,将值推入属性,然后返回它。如果匿名类型让你的生活变得更艰难,那么你就没有正确使用它们。

于 2009-08-25T17:32:25.533 回答
12

尽管有关于这是否是一个好主意的警告...... Adynamic似乎适用于私有方法。

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

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

您可以在LinqPad 中运行此示例。它将输出:

结果:test1,test2

于 2016-05-12T12:31:21.517 回答
4

不,匿名类型不能存在于创建它们的上下文之外,因此不能用作方法返回类型。您可以将实例返回为object,但为此目的显式创建自己的容器类型会更好。

于 2009-08-25T17:18:48.820 回答
4

我认为 Andrew Hare 是对的,你只需要返回“对象”。对于编辑评论,我觉得在 OO 代码中处理原始对象可能是一种“代码味道”。在某些情况下这样做是正确的,但大多数时候,如果要返回相关类型,最好定义一个要返回的接口,或者使用某种基类类型。

于 2009-08-25T17:20:50.657 回答
3

不,不支持在方法之外扩展匿名类的范围。在方法之外,类是真正匿名的,反射是访问它的成员的唯一方法。

于 2009-08-25T17:22:46.753 回答
2

对不起,你真的不应该那样做。您可以通过反射或通过创建通用辅助方法来为您返回类型来解决它,但这样做确实对语言不利。只需声明类型,以便清楚发生了什么。

于 2009-08-25T17:19:03.250 回答
2

如果可能,您还可以反转您的控制流:

    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]);

    }
于 2018-06-15T17:12:02.580 回答