【问题标题】:How can I get a value of a property from an anonymous type?如何从匿名类型中获取属性值?
【发布时间】:2010-10-26 20:40:12
【问题描述】:

我有一个由 Linq 查询填充的数据网格。当数据网格中的焦点行发生变化时,我需要设置一个变量,该变量等于该对象中的属性之一。

我试过了……

var selectedObject = view.GetRow(rowHandle);
_selectedId = selectedObject.Id;

...但编译器根本不关心这一点(“嵌入式语句不能是声明或标签语句”)。

似乎该属性应该易于访问。在运行时检查对象显示了我期望的所有属性,我只是不知道如何访问它们。

如何访问匿名对象的属性?

编辑澄清:

我碰巧在使用 DevExpress XtraGrid 控件。我用一个由几个不同对象组成的 Linq 查询加载了这个控件,因此使数据不符合我已经拥有的任何一个类(即,我不能将它转换为任何东西)。

我正在使用 .NET 3.5。

当我查看 view.GetRow(rowHandle) 方法的结果时,我得到一个匿名类型,如下所示:

{ ClientId = 7, ClientName = "ACME Inc.", Jobs = 5 }

我的目标是从这个匿名类型中获取 ClientId,以便我可以做其他事情(例如加载包含该客户记录的表单)。

我尝试了早期答案中的一些建议,但无法达到可以获取此 ClientId 的程度。

【问题讨论】:

  • 标识符“view”的确切类型是什么?
  • "View" 是 DevExpress 的 GridView 控件。

标签: c# .net anonymous-types


【解决方案1】:

您是否尝试过使用反射?这是一个示例代码sn-p:

// use reflection to retrieve the values of the following anonymous type
var obj = new { ClientId = 7, ClientName = "ACME Inc.", Jobs = 5 }; 
System.Type type = obj.GetType(); 
int clientid = (int)type.GetProperty("ClientId").GetValue(obj, null);
string clientname = (string)type.GetProperty("ClientName").GetValue(obj, null);

// use the retrieved values for whatever you want...

【讨论】:

  • 感谢 abdoul,您的代码很容易理解。我最近在获取匿名类型时遇到了问题,在这里:stackoverflow.com/questions/3534969/… 我留下了这个问题。在周末进行了一些搜索和工作后,我来到了这个页面,这真的让我很开心。
  • 这就是我喜欢 SO 的原因
  • 真的,太棒了答案!这就是我从 2 周开始搜索的内容!非常感谢!
  • @ogborstad 完成。 JaredPar 提供的答案在我回复时是最准确的。这个答案在 12 个月后出现,我同意,它更准确。 (我只花了 7 年的时间就注意到了。)
【解决方案2】:

获取给定键的数据项值的通用解决方案

public static T GetValueFromAnonymousType<T>( object dataitem, string itemkey ) {
    System.Type type = dataitem.GetType();
    T itemvalue = (T)type.GetProperty(itemkey).GetValue(dataitem, null);
    return itemvalue;
}

例子:

var dataitem = /* Some value here */;
bool ismember = TypeUtils.GetValueFromAnonymousType<bool>(dataitem, "IsMember");

【讨论】:

  • 我发现这个解决方案是声明匿名类型的下一个最佳选择。谢谢。
【解决方案3】:

匿名类型的一个问题是很难在函数之间使用它们。没有办法“命名”匿名类型,因此很难在它们之间进行转换。这可以防止它们被用作出现在元数据中并且是用户定义的任何内容的类型表达式。

我无法准确说出您在上面使用的是哪个 API。但是,API 不可能返回强类型的匿名类型,所以我猜测 selectedObject 的类型是对象。 C# 3.0 及更低版本不支持动态访问,因此您将无法访问属性 ID,即使它在运行时可用。

您需要执行以下操作之一才能解决此问题

  • 使用反射抓取属性
  • 创建一个完整类型并使用它来填充数据网格
  • 使用许多 hacky 匿名类型转换中的一种

编辑

这是一个关于如何进行 hack 匿名类型转换的示例

public T AnonymousTypeCast<T>(object anonymous, T typeExpression) { 
  return (T)anonymous;
}

...
object obj = GetSomeAnonymousType();
var at = AnonymousTypeCast(obj, new { Name = String.Empty, Id = 0 });

它很hacky的原因是它很容易破解。例如在最初创建匿名类型的方法中。如果我向该类型添加另一个属性,则上面的代码将编译但在运行时失败。

【讨论】:

  • “hacky 匿名类型转换”是什么?
  • @AnthonyWJones,我添加了一个 hacky 匿名类型转换的示例
  • 感谢您的回答。一个非常好的和优雅的解决方案。它只有一个缺点:如果匿名对象来自另一个程序集,它就不起作用。这就是为什么你永远不应该从一个方法返回一个匿名对象的原因之一,但并不是每个人都知道这一点,所以我不得不处理一个不幸的库。
【解决方案4】:

您可以使用动态类型在运行时访问匿名类型的属性,而无需使用反射。

var aType = new { id = 1, name = "Hello World!" };
//...
//...
dynamic x = aType;
Console.WriteLine(x.name); // Produces: Hello World!

在此处阅读有关动态类型的更多信息:http://msdn.microsoft.com/en-us/library/dd264736.aspx

【讨论】:

  • 如此简单优雅,我为没有想到它感到羞耻:)
【解决方案5】:

当我处理传递匿名类型并尝试重铸它们时,我最终发现编写一个处理对象处理的包装器更容易。这是一个关于它的博客文章的链接。

http://somewebguy.wordpress.com/2009/05/29/anonymous-types-round-two/

最终,您的代码将如下所示。

//create an anonymous type
var something = new {  
  name = "Mark",  
  age = 50  
};  
AnonymousType type = new AnonymousType(something);

//then access values by their property name and type
type.With((string name, int age) => {  
  Console.Write("{0} :: {1}", name, age);  
}); 

//or just single values
int value = type.Get<int>("age");   

【讨论】:

    【解决方案6】:

    正如 JaredPar 猜对的那样,GetRow() 的返回类型是 object。使用 DevExpress 网格时,您可以像这样提取所需的值:

    int clientId = (int)gridView.GetRowCellValue(rowHandle, "ClientId");
    

    这种方法也有类似之前描述的“hacky 匿名类型转换”的缺点:您需要一个用于标识列的魔术字符串以及从 object 到 int 的类型转换。

    【讨论】:

      【解决方案7】:

      DevExpress 的 xtraGridView 有一个类似 GetRowCellDisplayText(int rowHandle, GridColumn column) 的方法。使用此方法,以下代码从匿名类型返回 id。

      var _selectedId = view.GetRowCellDisplayText(rowHandle, "Id");
      

      虽然这没有回答“我如何才能访问匿名对象的属性?”这个问题,但它仍然试图解决问题的根本原因。

      我在 devXpress 版本 11.1 上尝试过这个,我可以看到这个问题是在大约 2.5 年前首次提出的。问题的作者可能已经找到了解决方法或自己找到了解决方案。但是,我仍在回答,以便对某人有所帮助。

      【讨论】:

        【解决方案8】:

        这可能是错误的(您可能没有足够的代码),但您不需要对行进行索引以便选择您想要的列吗?或者,如果“Id”是您想要的列,您应该这样做:

        var selectedObject = view.GetRow(rowHandle);
        _selectedId = selectedObject["Id"];
        

        这就是我在数据网格中获取列内容的方式。现在,如果列本身是匿名类型,那么我不知道,但如果您只是获得一个具有原始类型的命名列,那么这应该可以工作。

        【讨论】:

          【解决方案9】:

          希望这会有所帮助,我正在传递一个接口列表,我需要从中获取一个不同的列表。首先我得到一个 Anonymous 类型列表,然后我将其传送到我的对象列表中。

          private List<StockSymbolResult> GetDistinctSymbolList( List<ICommonFields> l )
                      {
                          var DistinctList = (
                                  from a
                                  in l
                                  orderby a.Symbol
                                  select new
                                  {
                                      a.Symbol,
                                      a.StockID
                                  } ).Distinct();
          
                          StockSymbolResult ssr;
                          List<StockSymbolResult> rl = new List<StockSymbolResult>();
                          foreach ( var i in DistinctList )
                          {
                                          // Symbol is a string and StockID is an int.
                              ssr = new StockSymbolResult( i.Symbol, i.StockID );
                              rl.Add( ssr );
                          }
          
                          return rl;
                      }
          

          【讨论】:

            【解决方案10】:

            您可以像这样遍历匿名类型的属性:

            var obj = new {someValue = "hello", otherValue = "world"};
            foreach (var propertyInfo in obj.GetType().GetProperties() {
                var name = propertyInfo.Name;
                var value = propertyInfo.GetValue(obj, index: null);
                ...
            }
            

            【讨论】:

              【解决方案11】:

              如果您知道自己在做什么,并且不怕在代码更改时出现运行时错误,您可以将行数据转换为 dynamic

              var data = view.GetRow(rowHandle) as dynamic;  
              
              int clientId      = data.ClientID;
              string clientName = data.ClientName;
              int jobs          = data.Jobs
              

              没有编译时验证。但它应该很好用。

              【讨论】:

                【解决方案12】:
                var result = ((dynamic)DataGridView.Rows[rowNum].DataBoundItem).value;
                

                【讨论】:

                • 这是获取列表属性值的最简单形式(DataGridView)
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-15
                • 1970-01-01
                • 2021-12-04
                • 2012-04-12
                • 1970-01-01
                相关资源
                最近更新 更多