Подтвердить что ты не робот

Получил ли .NET преимущества от названных анонимных типов?

Рассмотрим это:

var me = new { FirstName = "John", LastName = "Smith" };

Это прекрасно, как мы можем это сделать:

Console.WriteLine("{0} {1}", me.FirstName, me.LastName);

Однако мы не можем этого сделать:

public T GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

потому что мы не знаем тип T.

Мы могли бы сделать это:

public object GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

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

var p = new Prog();
object o = p.GetMe();
Type t = o.GetType();
foreach (var prop in t.GetProperties())
{
    Console.WriteLine(prop.Name + ": " + prop.GetValue(o, null));
}

Однако как насчет того, можно ли назвать анонимный тип, как мы его определяем? Конечно, это уже не было бы анонимным, однако оно было бы более кратким и содержательным, чем обычное определение класса.

Рассмотрим это:

public Person GetMe()
{
    return new public class Person { FirstName = "John", LastName = "Smith" };
}

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

Рассмотрим этот относительно сложный запрос Linq:

List<int> list = new List<int>();
var query = from number in list
            select
                new
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };

Вместо определения такого класса:

public class MyNumbers
{
    public int Number { get; set; }
    public int Square { get; set; }
    public int Absolute { get; set; }
    public IEnumerable<int> Range { get; set; }
}

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

List<int> list = new List<int>();
return from number in list
            select new public class MyNumbers
                    {
                        Number = number,
                        Square = number*number,
                        Absolute = Math.Abs(number),
                        Range = Enumerable.Range(0, number)
                    };
4b9b3361

Ответ 1

Собственно, есть "взломан", который вы можете сделать, чтобы вернуть анонимный тип из метода. Рассмотрим это:

public object MyMethod()
    {
        var myNewObject = new
        {
            stringProperty = "Hello, World!",
            intProperty = 1337,
            boolProperty = false
        };

        return myNewObject;
    }

    public T Cast<T>(object obj, T type)
    {
        return (T)obj;
    }

Теперь вы можете сделать это:

var obj = MyMethod();
var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });

Теперь myNewObj будет объектом того же типа, что и анонимный.

Ответ 2

Необходимая языковая функция:

public var GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

То есть var будет действительным как возвращаемый тип метода, и компилятор выведет фактический тип из возвращаемого. Затем вам нужно будет сделать это на сайте вызова:

var me = GetMe();

Любые два анонимных типа с членами одного типа будут одного типа, поэтому, если вы написали другие функции, возвращающие один и тот же шаблон, они будут иметь один и тот же тип. Для любых типов A и B, где B имеет подмножество членов A, то A является совместимым с B с B, как базовый класс A). Если вы написали:

public var GetMeFrom(var names)
{
    return new { FirstName = names["First"], LastName = names["Last"] };
}

Компилятор будет эффективно определять это как общий метод с двумя параметрами типа, T1 - тип имен, а T2 - тип, возвращаемый индексом на T1, который принимает строку. T1 будет ограничено, так что у него должен быть указатель, который принимает строку. И на сайте вызова вы просто передадите все, что имело индексатор, который принял строку и вернул любой тип, который вам нравится, и это будет определять тип FirstName и LastName в типе, возвращаемом GetMeFrom.

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

Ответ 3

ИМХО, проблема с корнем не имеет ничего общего с анонимными типами, но объявление класса слишком многословно.

Вариант 1:

Если вы можете объявить класс следующим образом:

public class MyClass
{ properties={ int Number, int Square, int Absolute, IEnumerable<int> Range } }

или какой-либо другой быстрый способ (например, пример кортежа), вы не почувствовали бы необходимость делать хакерские вещи с анонимными типами, чтобы сохранить некоторый код.

Когда "компилятор как услуга" прибывает на С# 5, мы надеемся, что они сделают хорошую работу по его интеграции, и мы сможем использовать метапрограммирование для решения этих проблем. Партия вроде 1958!

Вариант 2:

В качестве альтернативы, в С# 4 вы можете просто передать анонимный тип вокруг dynamic и избегать всех кастингов. Конечно, это открывает вам ошибки времени выполнения, если вы переименовываете переменную и т.д.

Вариант 3:

Если С# будет реализовывать обобщения так же, как С++, то вы можете передать анонимный тип в метод, и до тех пор, пока он имеет правильные члены, он просто компилируется. Вы получите все преимущества безопасности статического типа, и ни один из недостатков. Каждый раз, когда мне приходится набирать where T : ISomething в С#, меня раздражает, что они этого не делают!

Ответ 4

То, что вы описываете (называемые анонимными типами), в основном относится к типам кортежей.

Я думаю, что они были бы хорошим дополнением к С#.

Если бы я разрабатывал такую ​​функцию для С#, я бы разоблачил ее с помощью синтаксиса следующим образом:

tuple<int x, int y>

чтобы вы могли:

public tuple<int x, int y> GetStuff()
{
}

Затем я изменил бы определение анонимных типов, чтобы:

new { x = 2, y = 2}

имел tuple<int x, int y> по мере его ввода, а не анонимного типа.

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

Единственным недостатком этого подхода является то, что он не уважает CLR "ленивую" модель для генерации типа. Это означает, что сборки, которые используют множество разных типов кортежей, могут испытывать несколько более медленные типы нагрузки. Лучшим подходом было бы добавить поддержку типов кортежей непосредственно в CLR.

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

Ответ 5

Мне бы очень понравилась эта функция, я много раз хотел этого.

Хорошим примером является обработка XML. Вы разбираете их, чтобы вернуть объект, но тогда вам нужно сделать конкретную версию объекта, чтобы отправить обратно вызывающему. Много раз вы получаете XML, который изменяется довольно значительно и требует от вас многих классов для его обработки. Было бы замечательно, если бы вы могли просто построить объект с помощью LinqToXml в качестве var, а затем просто вернуть это?

Ответ 6

Я думаю, что это было бы приятной магией компилятора для кортежей:

Создание кортежа:

(int, string, Person) tuple = (8, "hello", new Person());

эквивалентно:

Tuple<int,string,Person> tuple = new Tuple<int,string,Person>(8 ,"hello", new Person());

В функции:

public (int, string, Person) GetTuple(){
    return ...
}

Получение значений:

int number = tuple[1];
string text = tuple[2];
Person person = tuple[3];

Ответ 7

Не могли бы вы создать интерфейс со свойствами FirstName и LastName и использовать это?