25

我有一个由 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 的程度。

4

12 回答 12

55

你有没有尝试过使用反射?这是一个示例代码片段:

// 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...
于 2010-07-28T23:33:38.793 回答
21

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

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");
于 2010-12-04T02:25:37.327 回答
17

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

我无法准确说出您在上面使用的是哪个 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的原因是它很容易破解。例如在最初创建匿名类型的方法中。如果我在该类型中添加另一个属性,上面的代码将编译但在运行时失败。

于 2009-05-17T14:46:56.610 回答
15

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

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

于 2012-03-30T07:04:33.707 回答
3

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

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");   
于 2009-05-29T16:25:40.947 回答
1

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

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

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

于 2009-05-17T16:49:25.097 回答
1

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

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

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

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

于 2011-12-28T05:29:09.930 回答
0

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

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

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

于 2009-05-17T15:03:17.693 回答
0

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

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;
            }
于 2010-10-11T23:05:29.807 回答
0

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

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);
    ...
}
于 2011-03-24T14:55:42.757 回答
0

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

var data = view.GetRow(rowHandle) as dynamic;  

int clientId      = data.ClientID;
string clientName = data.ClientName;
int jobs          = data.Jobs

没有编译时验证。但它应该工作得很好。

于 2013-07-23T08:36:34.753 回答
0
var result = ((dynamic)DataGridView.Rows[rowNum].DataBoundItem).value;
于 2015-12-30T21:45:50.347 回答