[Solved] Is there a way to return Anonymous Type from method?

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.

Enquirer: Cleiton

||

Solution #1:

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.

Respondent: Cleiton

Solution #2:

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;
Respondent: Andrew Hare

Solution #3:

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

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

Solution #4:

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}");
Respondent: Nana Kofi

Solution #5:

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.

Respondent: baur

Solution #6:

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

Respondent: Jagd

Solution #7:

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.

Respondent: controlbox

Solution #8:

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.

Respondent: Adam Robinson

Solution #9:

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.

Respondent: Andy White

Solution #10:

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.

Respondent: mqp

Solution #11:

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

    }
Respondent: Guffa

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.