简体   繁体   English

从C#中的通用对象获取属性

[英]Get Property from a generic Object in C#

have a look at this code please: 请看一下这段代码:

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

When in write in Visual Studio "item.XXX" I should get the properties from my entitiy like .FirstName or .LastName. 在Visual Studio“item.XXX”中编写时,我应该从我的权限中获取属性,如.FirstName或.LastName。 I do not know wether dataObjects is an IEnumerable or IOrder etc... it must be generic! 我不知道数据对象是IEnumerable还是IOrder等......它必须是通用的!

How can I get the real properties form item ? 如何获得真实属性表单项? Only with Reflection? 只有反思?

Oded is right , it doesn't seem (to him or me) to make any sense to try and make this method generic. Oded是对的 ,似乎(对他或我来说)没有任何意义来尝试使这种方法通用。 You are trying to genericize a method whose functionality is actually specific to a few types. 您正在尝试对其功能实际上特定于几种类型的方法进行泛化。

Now, that said, it seems the bulk of the function is independent of this property you want to access. 现在,也就是说,似乎该函数的大部分与您想要访问的此属性无关。 So why not split it into two parts: that which can be genericized, and that which can't: 那么为什么不将它分成两部分:可以泛化的部分,以及不能部署的部分:

Something like this: 像这样的东西:

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

Then your overloads dealing with specific types, eg, IPerson , can reuse this code (which I suspect may be what you were after all along—code reuse): 然后你处理特定类型的重载,例如IPerson ,可以重用这段代码(我怀疑它可能是你在所有代码重用之后所使用的):

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

...then for IOrder : ......然后是IOrder

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

...and so on. ...等等。

If you add a constraint to the generic type (say it has to implement the IPerson interface), you can use any methods defined on the interface: 如果向泛型类型添加约束 (比如它必须实现IPerson接口),则可以使用接口上定义的任何方法:

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

If IPerson defines FirstName and LastName peroperties, you can use them with T . 如果IPerson定义了FirstNameLastName peroperties,则可以将它们与T一起使用。

See the link for the different types of generic constraints possible. 请参阅链接以了解可能的不同类型的通用约束

Adding to Dan's answer, Func<T, TProperty> selector merely says that selector is an identifier for a method that takes in a parameter of type T and has a return type of TProperty . 添加到Dan的答案, Func<T, TProperty> selector只是说selector是一个方法的标识符,该方法接受类型为T的参数并且返回类型为TProperty So, a valid method that could be passed into BindElements as a second parameter would be, for example, 因此,可以作为第二个参数传递给BindElements的有效方法是,例如,

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

In this case, TProperty would be a string and T would IPerson . 在这种情况下, TProperty将是一个stringT将是IPerson You can then call BindElements like so 然后你可以这样调用BindElements

BindElements(myPersonCollection,CreatePersonElement);

where myPersonCollection can just be whatever List<T> you were referring to. 其中myPersonCollection可以是你所指的List<T> Then moving on to the foreach loop 然后继续前进到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 is being set to an object of type TProperty , which in the case of CreatePersonElement is a string . property被设置为TProperty类型的对象,在CreatePersonElement的情况下是一个string If a string doesn't work for you, just change the return type of the method to be whatever CreateElementContainer is accepting as its parameter. 如果string不适合您,只需将方法的返回类型更改为CreateElementContainer接受的任何参数。

You would then have one of these methods to pass into the second parameter for BindElements for each type you want to support (ie ICustomer , IOrder ). 然后,您可以将这些方法之一传递给您想要支持的每种类型的BindElements的第二个参数(即ICustomerIOrder )。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM