Есть ли способ вернуть анонимный тип из метода?


Я знаю, что не могу написать такой метод, как:

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

Я могу сделать это иначе:

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

но я не хочу делать второй вариант, потому что если я делаю так, мне придется использовать отражение.


почему я хочу сделать это:

сегодня у меня есть метод внутри моей страницы aspx, который возвращает datatable как результат, и я не могу изменить его, Я пытался преобразовать этот DataTable в анонимный метод со свойствами, которые я хочу для работы. Я не хотел создавать класс только для этого, и поскольку мне нужно будет выполнить один и тот же запрос более одного раза, я подумал, что создать метод, который возвращает анонимный тип, было бы хорошей идеей.

11 52

11 ответов:

возвращая его как System.Object - Это только способ возврата анонимного типа из метода. К сожалению, нет другого способа сделать это, так как анонимные типы были разработаны специально для предотвращения их использования таким образом.

есть некоторые трюки, которые вы можете сделать в сочетании с возвращением Object что позволит вам приблизиться. Если вы заинтересованы в этом обходном пути, пожалуйста, прочитайте не удается вернуть анонимный тип из метода? Правда?.

отказ от ответственности: несмотря на то, что статья, которую я связал, показывает обходной путь, который не означает, что это хорошая идея. Я бы настоятельно рекомендовал вам использовать этот подход, когда создание обычного типа будет более безопасным и простым для понимания.

кроме того, вы можете использовать класс кортежа в .NET 4.0 и выше:

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;
public object MyMethod() 
{
    return new
    {
         Property1 = "test",
        Property2 = "test"
     };
}

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

самое простое решение-создать класс, засунуть значения в свойство, а затем вернуть его. Если анонимные типы делают вашу жизнь сложнее, то вы не используете их правильно.

несмотря на предупреждения о том, является ли это хорошей идеей или нет... А dynamic Кажется, работает просто отлично для частного метода.

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

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

Вы можете запустить этот пример в LinqPad. он выведет:

результат: test1, test2

в качестве альтернативы, начиная 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}");

Я думаю, что Андрей Заяц прав, вам нужно просто вернуть "объект."Для редакционного комментария я чувствую, что работа с необработанными объектами в OO-коде может быть "запахом кода"."Есть случаи, когда это правильно, но в большинстве случаев вам лучше определить интерфейс для возврата или использовать какой-то тип базового класса, если вы собираетесь возвращать связанные типы.

нет, анонимные типы не могут существовать вне контекста, в котором они создаются, и в результате не могут использоваться в качестве возвращаемого типа метода. Вы можете вернуть экземпляр как object, но гораздо лучше явно создать свой собственный тип контейнера для этой цели.

Извините, вы действительно не должны этого делать. Вы можете взломать его с помощью отражения или сделать общий вспомогательный метод, чтобы вернуть тип для вас, но это действительно работает против языка. Просто объявите тип, чтобы было понятно, что происходит.

нет, нет поддержки для расширения области анонимного класса вне метода. Вне метода класс действительно анонимен, и отражение-единственный способ получить доступ к его членам.

вы также можете инвертировать поток управления, если это возможно:

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

    }