Is there a way to return Anonymous Type from method?

C#.NetAnonymous Types

C# Problem Overview


I know I can't write a method like:

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

I can do it otherwise:

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

but I don't want to do the second option because, if I do so, I will have to use reflection.


Why I want to do that:

Today i have a method inside my aspx page that returns a datatable as result and I cannot change it, I was trying to convert this DataTable to an Anonymous method with the properties that I want to work with. I didn't want to create a class only to do that and as I will need to perform the same query more than one time, I Thought to create a method that returns an anonymous type would be a good ideia.

C# Solutions


Solution 1 - C#

Returning it as a System.Object is the only way to return an anonymous type from a method. Unfortunately there is no other way to do this since anonymous types were designed specifically to prevent their use in this way.

There are some tricks that you can do to in conjunction with returning an Object that allow you to get close. If you are interested in this workaround please read Can't return anonymous type from method? Really?.

Disclaimer: Even though the article I linked does show a workaround that doesn't mean it is a good idea to do it. I would strongly discourage you using this approach when creating a regular type would be safer and easier to understand.

Solution 2 - C#

Alternatively, you can use the Tuple class in .NET 4.0 and higher:

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

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

then you can access the properties like this:

var result = Create();
result.Item1;
result.Item2;

Solution 3 - C#

As alternative, starting C# 7 we can use ValueTuple. A little example from 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;
}

And on the receiving end:

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

Or:

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

Solution 4 - C#

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

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

Solution 5 - C#

The easiest solution is to create a class, shove the values into the property, and then return it. If anonymous types are making your life harder then you're not using them correctly.

Solution 6 - C#

Notwithstanding the warnings about whether this is a good idea or not... A dynamic seems to work just fine for a private method.

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

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

You can run this example in LinqPad. It will output:

> Result: test1, test2

Solution 7 - C#

No, anonymous types cannot exist outside of the context in which they are created, and as a result cannot be used as a method return type. You can return the instance as an object, but it's a much better idea to explicitly create your own container type for this purpose.

Solution 8 - C#

I think Andrew Hare is right, you'd have to just return "object." For an editorial comment, I feel like dealing with raw objects in OO code can be a "code smell." There are cases where it's the right thing to do, but most of the time, you'd be better off defining an interface to return, or using some sort of base class type, if you're going to be returning related types.

Solution 9 - C#

No, there is no support for expanding the scope of the anonymous class outside the method. Outside of the method the class is truly anonymous, and reflection is the only way to access it's members.

Solution 10 - C#

Sorry, you really aren't supposed to do that. You can hack around it with reflection or by making a generic helper method to return the type for you, but doing so is really working against the language. Just declare the type so it's clear what's going on.

Solution 11 - C#

You could also invert your control flow if possible:

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

and then later somwhere else:

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

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCleitonView Question on Stackoverflow
Solution 1 - C#Andrew HareView Answer on Stackoverflow
Solution 2 - C#The LightView Answer on Stackoverflow
Solution 3 - C#baurView Answer on Stackoverflow
Solution 4 - C#Nana KofiView Answer on Stackoverflow
Solution 5 - C#JagdView Answer on Stackoverflow
Solution 6 - C#controlboxView Answer on Stackoverflow
Solution 7 - C#Adam RobinsonView Answer on Stackoverflow
Solution 8 - C#Andy WhiteView Answer on Stackoverflow
Solution 9 - C#GuffaView Answer on Stackoverflow
Solution 10 - C#mqpView Answer on Stackoverflow
Solution 11 - C#sneusseView Answer on Stackoverflow