Is there a way to return Anonymous Type from method?
C#.NetAnonymous TypesC# 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]);
}