代码之家  ›  专栏  ›  技术社区  ›  Cleiton

是否有方法从方法返回匿名类型?

  •  56
  • Cleiton  · 技术社区  · 15 年前

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

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

    否则我可以这样做:

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

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


    我为什么要这样做:

    今天,我在ASPX页面中有一个方法,它返回一个作为结果的数据表,并且我 无法更改 ,我试图将此数据表转换为具有要使用的属性的匿名方法。我不想只创建一个类来实现这一点,因为我需要多次执行相同的查询,所以我认为创建一个返回匿名类型的方法是一个很好的IDIA。

    11 回复  |  直到 6 年前
        1
  •  62
  •   Andrew Hare    15 年前

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

    在返回 Object 这样你就可以接近了。如果您对这个解决方案感兴趣,请阅读 Can't return anonymous type from method? Really? .

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

        2
  •  23
  •   Lightning3    10 年前

    或者,可以使用.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;
    
        3
  •  17
  •   abatishchev Marc Gravell    7 年前
    public object MyMethod() 
    {
        return new
        {
             Property1 = "test",
            Property2 = "test"
         };
    }
    
    static void Main(..)
    {
        dynamic o = MyMethod();  
        var p1 = o.Property1;
        var p2 = o.Property2;
    }
    
        4
  •  15
  •   Jagd Dai    15 年前

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

        5
  •  10
  •   Adam    6 年前

    作为替代方案,从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}");
    
        6
  •  8
  •   Matt    6 年前

    尽管有警告说这是不是个好主意…A dynamic 对于一个私有的方法来说似乎工作得很好。

    void Main()
    {
        var result = MyMethod();
        Console.WriteLine($"Result: {result.Property1}, {result.Property2}");
    }
    
    public dynamic MyMethod()
    {
        return new { Property1 = "test1", Property2 = "test2" };
    }
    

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

    结果:测试1,测试2

        7
  •  3
  •   Andy White    15 年前

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

        8
  •  2
  •   Adam Robinson    15 年前

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

        9
  •  2
  •   mqp    15 年前

    对不起,你真的不应该这样做。您可以通过反射或生成一个通用的帮助器方法为您返回类型来绕过它,但这样做实际上是对语言不利的。只需声明类型,就可以清楚地知道发生了什么。

        10
  •  2
  •   Guffa    15 年前

    不,不支持将匿名类的作用域扩展到方法之外。在方法之外,类是真正匿名的,反射是访问其成员的唯一方法。

        11
  •  2
  •   sneusse    6 年前

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

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