【问题标题】:Get Property from a generic Object in C#从 C# 中的通用对象获取属性
【发布时间】:2010-11-27 16:56:20
【问题描述】:

请看一下这段代码:

public void BindElements<T>(IEnumerable<T> dataObjects)
{
    Paragraph para = new Paragraph();

    foreach (T item in dataObjects)
    {
        InlineUIContainer uiContainer =
            this.CreateElementContainer(item.FirstName ????? )              
        para.Inlines.Add(uiContainer);
    }                         

    FlowDocument flowDoc = new FlowDocument(para);
    this.Document = flowDoc;
}

在 Visual Studio 中写入“item.XXX”时,我应该从我的实体中获取属性,例如 .FirstName 或 .LastName。我不知道 dataObjects 是 IEnumerable 还是 IOrder 等......它必须是通用的!

我怎样才能得到真实的属性表单项?只有反射?

【问题讨论】:

  • 我认为它比 public void BindElements(object dataObjects) 更好,因为我必须做演员......

标签: c# object get properties generics


【解决方案1】:

Oded is right,(对他或我来说)尝试使这种方法通用化似乎没有任何意义。您正在尝试泛化一个方法,其功能实际上是特定于几种类型的。

现在,也就是说,函数的 bulk 似乎与您要访问的这个属性无关。那么为什么不把它分成两部分:可以泛化的和不能泛化的:

类似这样的:

void BindElements<T, TProperty>(IEnumerable<T> dataObjects,
                                Func<T, TProperty> selector)
{
    Paragraph para = new Paragraph();

    foreach (T item in dataObjects)
    {
       // Notice: by delegating the only type-specific aspect of this method
       // (the property) to (fittingly enough) a delegate, we are able to 
       // package MOST of the code in a reusable form.
       var property = selector(item);

       InlineUIContainer uiContainer = this.CreateElementContainer(property)
       para.Inlines.Add(uiContainer);
    }

    FlowDocument flowDoc = new FlowDocument(para);
    this.Document = flowDoc;
}

然后你处理特定类型的重载,例如IPerson,可以重用这段代码(我怀疑这可能是你一直以来的样子——代码重用):

public void BindPeople(IEnumerable<IPerson> people)
{
    BindElements(people, p => p.FirstName);
}

...那么对于IOrder:

public void BindOrders(IEnumerable<IOrder> orders)
{
    BindElements(orders, o => p.OrderNumber);
}

...等等。

【讨论】:

  • 啊,我以为我已经评论过这个了,好吧,我现在这样做......:@Dan Tao => 如果我想传递两个像 FirstName 和 LastName 这样的“选择器”,该怎么办? BindElements 方法参数变化?我从来没有播种/阅读过那个 TProperty + 选择器,我也不太了解它;-) 刚开始做真正通用的通用东西。
  • +1 - 绝对是一个有利的实现,我在想 Func 可能是她创建元素容器的某种工厂方法。
【解决方案2】:

如果你将constraint添加到泛型类型(假设它必须实现IPerson接口),你可以使用接口上定义的任何方法:

public void BindElements<T>(IEnumerable<T> dataObjects) where T : IPerson

如果IPerson 定义了FirstNameLastName 属性,您可以将它们与T 一起使用。

查看链接了解可能的不同类型的generic constraints

【讨论】:

  • 打败我。我的答案几乎完全一样。
  • @Oded 很抱歉混淆它不应该意味着......是一个 IEnumerable 它应该意味着 ICustomer 或 IOrder 等......但你已经得到它几乎......问题是我不能把 IPerson因为那会破坏该方法的通用功能!公开 BindElements 方法的 UserControl 的用户正在传递一个 List 或 IEnumerable 并且 T 可以是 IPerson 或 ICustomer 或 IOrder,你明白了吗?
  • @Lisa - 但是通过希望有 specific 方法来调用您的泛型参数,您已经“破坏”了函数的泛型特性。请解释为什么几个重载不会比一个混蛋泛型函数更好地工作?
  • @Oded 如果不同的实体不都具有 FirstName 属性,无论是否反射,她的混蛋通用函数都将无法工作。
  • @siride - 很清楚这一点。这就是为什么我首先质疑通用方法。
【解决方案3】:

添加到 Dan 的回答中,Func&lt;T, TProperty&gt; selector 只是说selector 是一个方法的标识符,该方法接受T 类型的参数并具有TProperty 的返回类型。因此,可以作为第二个参数传递给BindElements 的有效方法是,例如,

string CreatePersonElement(IPerson person) {
    return string.Format("{0} {1}", person.FirstName, person.LastName);
}

在这种情况下,TProperty 将是 stringT 将是 IPerson。然后你可以像这样调用BindElements

BindElements(myPersonCollection,CreatePersonElement);

myPersonCollection 可以是您所指的任何 List&lt;T&gt;。然后继续 foreach 循环

foreach (T item in dataObjects) {
   // Notice: by delegating the only type-specific aspect of this method
   // (the property) to (fittingly enough) a delegate, we are able to 
   // package MOST of the code in a reusable form.
   var property = selector(item);

   InlineUIContainer uiContainer = this.CreateElementContainer(property)
   para.Inlines.Add(uiContainer);
}

property 被设置为TProperty 类型的对象,在CreatePersonElement 的情况下是string。如果 string 不适合您,只需将方法的返回类型更改为 CreateElementContainer 接受的任何参数即可。

然后,对于您想要支持的每种类型(即ICustomerIOrder),您可以将其中一种方法传递给BindElements 的第二个参数。

【讨论】:

  • 不是按位的解决方案,但值得一提:P 感谢您的示例!
  • 不客气 - 是的,丹的解决方案绝对值得称赞 =)
【解决方案4】:

我会阅读 http://msdn.microsoft.com/en-us/library/d5x73970.aspx 并再次考虑 Oded 的答案。

【讨论】:

    猜你喜欢
    • 2022-11-08
    • 1970-01-01
    • 2011-04-09
    • 2014-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多