Возврат анонимного типа в C #

У меня есть запрос, который возвращает анонимный тип, и запрос находится в методе. Как вы пишете это:

<code>public "TheAnonymousType" TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new { SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return "TheAnonymousType";
    }
}
</code>
 HaveNoDisplayName08 мар. 2017 г., 14:35
Возможный дубликатIs there a way to return Anonymous Type from method?
 Yuck09 апр. 2012 г., 14:43
Почему вы хотите вернуть анонимный тип? Как вы могли бы использовать этот результат в другом месте?
 aw0404 авг. 2014 г., 21:02
@ Да что, если вы возвращаете json или что-то еще, где тип c # не имеет значения
 nawfal03 февр. 2014 г., 10:21
возможный дубликатHow can I return an anonymous type from a method?
 Kevbo11 нояб. 2015 г., 16:59
Я не думаю, что этот вопрос не обоснован. Я действительно должен был сделать это несколько раз. Это становится более очевидным при использовании сущностной инфраструктуры, и вы хотите выполнить запрос в одной функции и использовать результаты в нескольких местах. Мне это нужно довольно часто при отображении результатов на экране, а затем при необходимости использовать те же результаты в отчете или при экспорте в Excel. Запрос может содержать множество фильтров и тому подобное из пользовательского интерфейса. Вы действительно не хотите создавать один и тот же запрос в нескольких местах, или вы можете легко выйти из синхронизации, если хотите добавить к результатам

Ответы на вопрос(14)

public List<object> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new { SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return TheQueryFromDB ;
    }
}

осто проверяет пространства имен, иерархии классов, сигнатуры методов и т. Д. Тела методов компилируются только на втором этапе.

Анонимные типы не определяются до тех пор, пока тело метода не будет скомпилировано.

Таким образом, компилятор не может определить тип возвращаемого значения метода на первом этапе.

По этой причине анонимные типы не могут использоваться в качестве возвращаемого типа.

Как другие предложили, если вы используете .net 4.0 или терку, вы можете использоватьDynamic.

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

C# 7.0 мы все еще не можем возвращать анонимные типы, но у нас есть поддержкаtuple types и, таким образом, мы можем вернуть коллекциюtuple (System.ValueTuple<T1,T2> в этом случае).

Самая короткая версия кода, который вы хотите, может выглядеть так:

public List<(int SomeVariable, object AnotherVariable)> TheMethod()
{
    ...

    return (from data in TheDC.Data
            select (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject)
            ).ToList();
}

Или используя свободный синтаксис Linq:

return TheDC.Data
    .Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))
    .ToList();

C# 7.1 мы можем опустить имена свойств кортежа, и они будут выведены из инициализации кортежа, как это работает с анонимными типами:

select (data.SomeInt, data.SomeObject)
// or
Select(data => (data.SomeInt, data.SomeObject))

Вы можете вернутьсяdynamic которая даст вам проверенную во время выполнения версию анонимного типа, но только в .NET 4+

Решение Вопроса

Вы можете только вернутьсяobjectили контейнер объектов, напримерIEnumerable<object>, IList<object>, так далее.

 09 апр. 2012 г., 14:43
Или жеdynamic, Это немного облегчает работу.
 frenchie09 апр. 2012 г., 14:43
ну хорошо, так что вы можете использовать только анонимные типы внутри метода, но не в качестве возвращаемых значений?
 09 апр. 2012 г., 14:48
С помощьюdynamic не является решением, поля анонимного типа не являются открытыми, они являются внутренними.
 09 апр. 2012 г., 14:45
@frenchie: да, только внутри тела участника. Если вы хотите его вернуть - сделайте его широко известным типом.
 09 апр. 2012 г., 15:11
@HansPassant Если предположить, что вызывающая сторона находится в той же сборке, то это все еще (несколько) полезно. Для чего бы то ни было, поля являются открытыми - тип является внутренним. Я обычно нахожусь в лагере, что вы все равно не должны возвращать анонимный тип.

Опция 1:

public class TheRepresentativeType {
    public ... SomeVariable {get;set;}
    public ... AnotherVariable {get;set;}
}

public IEnumerable<TheRepresentativeType> TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

     return TheQueryFromDB;
   } 
}

Вариант 2:

public IEnumerable TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();
     return TheQueryFromDB;
   } 
}

Вы можете повторить это как объект

Вариант 3:

public IEnumerable<dynamic> TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

     return TheQueryFromDB; //You may need to call .Cast<dynamic>(), but I'm not sure
   } 
}

и вы сможете использовать его как динамический объект и напрямую обращаться к его свойствам

но вы всегда можете сделать это, передав делегат, который создает анонимный тип.

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

// returning an anonymous type
// look mom no casting
void LookMyChildReturnsAnAnonICanConsume()
{
    // if C# had first class functions you could do
    // var anonyFunc = (name:string,id:int) => new {Name=name,Id=id};
    var items = new[] { new { Item1 = "hello", Item2 = 3 } };
    var itemsProjection =items.Select(x => SomeLogic(x.Item1, x.Item2, (y, i) => new { Word = y, Count = i} ));
    // same projection = same type
    var otherSourceProjection = SomeOtherSource((y,i) => new {Word=y,Count=i});
    var q =
        from anony1 in itemsProjection
        join anony2 in otherSourceProjection
            on anony1.Word equals anony2.Word
        select new {anony1.Word,Source1Count=anony1.Count,Source2Count=anony2.Count};
    var togetherForever = itemsProjection.Concat(otherSourceProjection).ToList();
}

T SomeLogic<T>(string item1, int item2, Func<string,int,T> f){
    return f(item1,item2);
}
IEnumerable<T> SomeOtherSource<T>(Func<string,int,T> f){
    var dbValues = new []{Tuple.Create("hello",1), Tuple.Create("bye",2)};
    foreach(var x in dbValues)
        yield return f(x.Item1,x.Item2);
}

   dynamic obj = GetAnonymousType();

   Console.WriteLine(obj.Name);
   Console.WriteLine(obj.LastName);
   Console.WriteLine(obj.Age); 


   public static dynamic GetAnonymousType()
   {
       return new { Name = "John", LastName = "Smith", Age=42};
   }

Но с ключевым словом динамического типа вы потеряете безопасность времени компиляции, IDE IntelliSense и т. Д ...

public List<(int SomeVariable, string AnotherVariable)> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                       select new { SomeVariable = ....,
                                    AnotherVariable = ....}
                       ).ToList();

      return TheQueryFromDB.Select(s => (SomeVariable = s.SomeVariable, AnotherVariable = s.AnotherVariable)).ToList();
  }
}

Вам может понадобиться установитьSystem.ValueTuple Пакет Nuget, хотя.

которую можно вернуть? В противном случае вы должны использоватьobject.

Вот статья, написанная Джоном Скитом на эту тему

Код из статьи:

using System;

static class GrottyHacks
{
    internal static T Cast<T>(object target, T example)
    {
        return (T) target;
    }
}

class CheesecakeFactory
{
    static object CreateCheesecake()
    {
        return new { Fruit="Strawberry", Topping="Chocolate" };
    }

    static void Main()
    {
        object weaklyTyped = CreateCheesecake();
        var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
            new { Fruit="", Topping="" });

        Console.WriteLine("Cheesecake: {0} ({1})",
            stronglyTyped.Fruit, stronglyTyped.Topping);            
    }
}

Или вот еще одна похожая статья

Или, как другие комментируют, вы можете использоватьdynamic

 13 сент. 2016 г., 22:56
привет, спасибо +1!
 13 сент. 2016 г., 22:55
@ R & # xE9; mi Я обновил ссылку
 frenchie09 апр. 2012 г., 14:43
Конечно, я могу создать тип; Я хотел избежать этого.
 13 сент. 2016 г., 22:48
первая ссылка не работает, разве вы не знаете, была ли она перенесена в другое место?

вы будете конвертировать в любой тип из вашего анонимного возвращаемого объекта, если длинные открытые свойства совпадают. Ключевыми моментами являются, возвращая объект, использовать linq и autommaper. (или используйте аналогичную идею, возвращающую сериализованный JSON и т. д. или используйте отражение ...)

using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var data = GetData();

            var firts = data.First();

            var info = firts.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).First(p => p.Name == "Name");
            var value = info.GetValue(firts);

            Assert.AreEqual(value, "One");
        }


        [TestMethod]
        public void TestMethod2()
        {
            var data = GetData();

            var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
            var mapper = config.CreateMapper();

            var users = data.Select(mapper.Map<User>).ToArray();

            var firts = users.First();

            Assert.AreEqual(firts.Name, "One");

        }

        [TestMethod]
        public void TestMethod3()
        {
            var data = GetJData();


            var users = JsonConvert.DeserializeObject<User[]>(data);

            var firts = users.First();

            Assert.AreEqual(firts.Name, "One");

        }

        private object[] GetData()
        {

            return new[] { new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } };
        }

        private string GetJData()
        {

            return JsonConvert.SerializeObject(new []{ new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } }, Formatting.None);
        }

        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }

}
public List<SomeClass> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new SomeClass{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return TheQueryFromDB.ToList();
    }
}

public class SomeClass{
   public string SomeVariable{get;set}
   public string AnotherVariable{get;set;}
}

ием, которое я знаю. Насколько я знаю, вы не можете использовать возвращаемые значения анонимного типа в другом методе, поскольку он не будет просто распознан. Однако они могут использоваться в одном и том же методе. метод. Я использовал их какIQueryable или жеIEnumerableхотя он все еще не позволяет увидеть, что находится внутри переменной анонимного типа.

Я сталкивался с чем-то подобным до того, как пытался изменить код, вы можете проверить это здесь:Рефакторинг и создание отдельных методов

public object tst() {
    var a = new {
        prop1 = "test1",
        prop2 = "test2"
    };

    return a;
}


public string tst2(object anonymousObject, string propName) {
    return anonymousObject.GetType().GetProperties()
        .Where(w => w.Name == propName)
        .Select(s => s.GetValue(anonymousObject))
        .FirstOrDefault().ToString();
}

Образец:

object a = tst();
var val = tst2(a, "prop2");

Выход:

test2

когда требуется возврат:

Примечание: кортеж может иметь до 8 параметров.

return Tuple.Create(variable1, variable2);

Или, например, из оригинального сообщения:

public List<Tuple<SomeType, AnotherType>> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select Tuple.Create(..., ...)
                           ).ToList();

      return TheQueryFromDB.ToList();
    }
}

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

Ваш ответ на вопрос