如何从匿名类型获取属性的值?

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

我试过了…

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的程度。

你有没有试过用reflection? 这是一个示例代码段:

 // 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... 

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

 public static T GetValueFromAnonymousType( 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(dataitem, "IsMember"); 

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

我无法确切地说出您正在使用的API。 但是,API不可能返回强类型的匿名类型,因此我对该对象的猜测是对象类型。 C#3.0及更低版本不支持动态访问,因此即使在运行时可用,您也无法访问属性Id。

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

  • 使用reflection获取属性
  • 创建一个完整类型并使用它来填充数据网格
  • 使用众多hacky匿名类型转换之一

编辑

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

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

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

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

 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

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

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("age"); 

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

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

这种方法有类似的缺点,比如之前描述的“hacky anonymous type casts”:你需要一个魔术字符串来识别列以及从object到int的类型转换。

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

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

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

我用devXpress版本11.1尝试了这个,我可以看到这个问题是在大约2。5年前首次提出的。 可能问题的作者可能有一个解决方法或自己找到解决方案。 然而,我仍在回答,以便它可以帮助某人。

这可能是错误的(你可能没有足够的代码)但是你不需要索引到行中,所以你选择你想要的列? 或者,如果“Id”是您想要的列,您应该执行以下操作:

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

这就是我如何获取数据网格中列的内容。 现在,如果列本身是一个匿名类型,那么我不知道,但如果您只是获得一个带有基本类型的命名列,那么这应该可行。

希望这有帮助,我传递一个接口列表,我需要从中获取一个独特的列表。 首先,我得到一个匿名类型列表,然后我将它转移到我的对象列表。

 private List GetDistinctSymbolList( List l ) { var DistinctList = ( from a in l orderby a.Symbol select new { a.Symbol, a.StockID } ).Distinct(); StockSymbolResult ssr; List rl = new List(); 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; } 

您可以循环遍历匿名类型的属性,如下所示:

 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); ... } 

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

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

没有编译时validation。 但它应该很好地工作。

 var result = ((dynamic)DataGridView.Rows[rowNum].DataBoundItem).value;