C#匿名类型如何从其他方法中访问

9

我有一个ComboBox,其中填充了匿名类型的集合:

var results = (from row in data.Tables[0].AsEnumerable()
               select new { 
                    Id = row.Field<int>("id"),
                    Name = row.Field<string>("Name
               }).Distinct();

myComboBox.ValueMember = "Id";
myComboBox.DisplayMember = "Name";

foreach (var n in results)
{
    myComboBox.Items.Add(n);
}

然后,在comboBox的SelectedIndexChanged方法中,我想检索所选项目的Id,但是我无法访问“Id”属性,在myComboBox.SelectedItem中是所选对象。

private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
    if (myComboBox.SelectedItem != null)
    {
        var x = myComboBox.SelectedItem;

            ¿¿¿ ???
    }  
}

有什么想法吗?

如果你只需要ID,可以使用myCombobox.SelectedValue吗? - saus
2
使用 动态 关键字会让你陷入麻烦。匿名类型的成员具有 内部 可访问性。换句话说,当 UI 代码位于单独的程序集中时,您无法访问它们。将 UI 与数据模型分离非常常见且值得追求。在这里,简单地不要使用匿名类型就可以了。 - Hans Passant
在这里使用匿名和/或动态类型并不是答案。你自己的轻量级类型有什么问题呢?(或者对于这个特定的例子,KeyValuePair<int,string>?) - LukeH
或者使用 Tuple<int, string>,它比 KeyValuePair 更通用。 - neontapir
7个回答

9
由于您将Id作为valumember使用,因此该Id将存储为myComboBox.SelectedItem.Value。

4
你也可以使用反射技术。
private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
    if (myComboBox.SelectedItem != null)
    {
        var x = myComboBox.SelectedItem;
        System.Type type = x.GetType();
        int id = (int)type.GetProperty("Id").GetValue(obj, null);
    }  
}

1
类型转换技巧比反射快得多,虽然我不能确定它们中哪一个更有可能在未来的C#/CLR版本中继续工作。 - Michael Edenfield

3

1

我认为在这里最好使用类似 Tuple<int, string> 的东西,而不是匿名类型,但是你可以做你想做的事情。在同一个程序集中具有相同字段名称、字段类型和相同顺序的两个匿名类型会被内部"折叠"为一个类型。您可以使用此方法传递匿名类型实例,并使用泛型类型推断在以后将它们强制转换为特定类型。

请注意,这依赖于 C# 编译器中的内部机制,因此不能保证它将继续工作;但是,在每个具有匿名类型的当前版本的 C# 中都可以正常工作。

更新:实际上,C# 规范明确指出了这一点,因此完全可以这样做:

在同一程序中,指定相同名称、类型和顺序的一系列属性的两个匿名对象初始化程序将生成相同匿名类型的实例

还要注意,这只在单个程序集内起作用(不要让规范对“程序”的引用使您感到困惑)。要从另一个程序集中使用匿名类型需要反射(在我看来,这通常是一个非常糟糕的想法)。但是,在数据绑定场景(如您的场景)中,它可以正常工作。

public object foo; 

public void Create()
{
  this.foo = new { Id = 1, Name = "Melvin" };
}

public void Consume()
{
  var x = new { Id = 0, Name = String.Empty };
  var y = this.Cast(this.foo, x);
}

public T Cast<T> ( object o, T template )
{
  return (T)o;
}

我很惊讶这个答案没有得到更多的赞 - 我认为它非常棒!谢谢。 - Remi Despres-Smyth

1

如果你正在使用C# 4.0,那么请使用dynamic关键字。否则,请定义一个包含id和name的类来代替使用匿名类型,或者使用反射。


1
你需要最简单的解决方案吗?创建一个名为SimpleEntity的类,其中包含三个字段:Id、Description和Tag。这个类应该有一个构造函数,接受一个Object对象,并使用反射获取Id和Name并设置这两个字段。同时,你也要将Tag属性设置为该Object对象。这样,你只需要使用这个新类填充下拉框,然后就可以得到原始对象了。 希望这能帮到你。

如果构造函数接受三个参数(int,string,object),则可以避免使用反射。 - Francisco Goldenstein

0

您可以使用 dynamic 关键字代替 var


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接