Приведение к анонимному типу - PullRequest
49 голосов
/ 11 сентября 2009

У меня была следующая проблема сегодня, и мне было интересно, есть ли решение для моей проблемы.

Моя идея состояла в том, чтобы создать анонимные классы и использовать их в качестве источника данных для WinForm BindingSource:

public void Init()
{
    var option1 = new
                  {
                      Id = TemplateAction.Update,
                      Option = "Update the Templates",
                      Description = "Bla bla 1."
                  };

    var option2 = new
                  {
                      Id = TemplateAction.Download,
                      Option = "Download the Templates",
                      Description = "Bla bla 2."
                  };

    var list = new[] {option1, option2}.ToList();

    bsOptions.DataSource = list; // my BindingSource

    // cboTemplates is a ComboBox
    cboTemplates.DataSource = bsOptions; 
    cboTemplates.ValueMember = "Id";
    cboTemplates.DisplayMember = "Option";

    lblInfoTemplates.DataBindings.Add("Text", bsOptions, "Description");
}

Пока все отлично.

Проблема, с которой я столкнулся, заключается в том, чтобы извлечь Id из свойства «Current» BindingSource, потому что я не могу привести его обратно к Anonymous Type:

private void cmdOK_Click(object sender, EventArgs e)
{
    var option = (???)bsOptions.Current;
}

Я думаю, что нет способа узнать тип "Current" и получить доступ к свойству "Id"? Может быть, у кого-то есть хорошее решение ...

Я знаю, что есть и другие (а также более эффективные) способы получения идентификатора (Reflection, чтение значения из ComboBox, без использования анонимных tpyes, ...) Я просто взволнован, если есть возможность получить Type bsOptions.Current элегантным способом.

Ответы [ 7 ]

84 голосов
/ 11 сентября 2009

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


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

using System;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new { Id = 1, Name = "Bob" };
            TestMethod(a);

            Console.Out.WriteLine("Press enter to exit...");
            Console.In.ReadLine();
        }

        private static void TestMethod(Object x)
        {
            // This is a dummy value, just to get 'a' to be of the right type
            var a = new { Id = 0, Name = "" };
            a = Cast(a, x);
            Console.Out.WriteLine(a.Id + ": " + a.Name);
        }

        private static T Cast<T>(T typeHolder, Object x)
        {
            // typeHolder above is just for compiler magic
            // to infer the type to cast x to
            return (T)x;
        }
    }
}

Хитрость заключается в том, что внутри сборки один и тот же анонимный тип (те же свойства, тот же порядок) разрешается в один и тот же тип, что делает вышеописанный трюк.

private static T CastTo<T>(this Object value, T targetType)
{
    // targetType above is just for compiler magic
    // to infer the type to cast value to
    return (T)value;
}

использование:

var value = x.CastTo(a);

Но мы действительно раздвигаем границы здесь. Используйте реальный тип, он будет выглядеть и чувствовать себя чище.

19 голосов
/ 20 мая 2012

Вместо приведения к пользовательскому типу попробуйте использовать динамический тип.

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

private void cmdOK_Click(object sender, EventArgs e)
{
    dynamic option = bsOptions.Current;
    if (option.Id == 1) { doSomething(); }
      else { doSomethingElse(); }
}
8 голосов
/ 11 сентября 2009

Цитировать MSDN :

Анонимный тип не может быть приведен ни к какому интерфейсу или типу, кроме объекта.

6 голосов
/ 11 сентября 2009

В C # 3.0 это невозможно. Вам придется подождать C # 4.0, который позволяет получить доступ к свойствам во время выполнения с помощью «динамических» переменных.

2 голосов
/ 03 апреля 2012
public class MyExtensMethods{

    public static T GetPropertyValue<T>(this Object obj, string property)
    {
        return (T)obj.GetType().GetProperty(property).GetValue(obj, null);
    }
}

class SomeClass
{
    public int ID{get;set;}
    public int FullName{get;set;}
}


// casts obj to type SomeClass
public SomeClass CastToSomeClass(object obj)
{
     return new SomeClass()
     {
         ID = obj.GetPropertyValue<int>("Id"),
         FullName = obj.GetPropertyValue<string>("LastName") + ", " + obj.GetPropertyValue<string>("FirstName")
     };
}

.... тогда для произнесения ты сделаешь:

var a = new { Id = 1, FirstName = "Bob", LastName="Nam" };
SomeClass myNewVar = CastToSomeClass(a);
1 голос
/ 04 февраля 2011

Вы также можете объявить массив анонимных типов напрямую с этим синтаксисом:

var data = new [] {
  new {Id = 0, Name = "Foo"},
  new {Id = 42, Name = "Bar"},
};
1 голос
/ 11 сентября 2009

Вы можете попробовать это:

private void cmdOK_Click(object sender, EventArgs e)
{
    var option = Cast(bsOptions.Current, new { Id = 0, Option = "", Description = "" });
}

см .: Не можете вернуть анонимный тип из метода? Действительно?

...