2012-06-20 10 views
9

Ich möchte eine HTML-Tabelle aus ein paar angegebenen Parametern generieren. Insbesondere wollen die beiden Parameter ich in meine Methode zu übergeben sind: IEnumerable-Liste, und einige Teilmenge der Eigenschaften von T. Zum Beispiel lassen Sie uns sagen, dass ich eine Liste dieser Klasse haben:Generieren Sie HTML-Tabelle aus der Liste der generischen Klasse mit den angegebenen Eigenschaften

class Person 
{ 
    string FirstName 
    string MiddleName 
    string LastName 
} 

Lasst uns die Liste sagen hat 5 Leute darin. Ich möchte in der Lage, eine HTML-Tabelle dieser Klasse (oder jede andere beliebige Klasse) zu erhalten, indem so etwas wie dies zu tun:

List<Person> people; 
...add people to list 

string HTML = GetMyTable(people, "FirstName", "LastName"); 

Ich bin sicher, es gibt einen besseren Weg, um festzulegen, welche Eigenschaften ich die Tabelle wollen erzeugt von (oder welche Eigenschaften ich von der Tabelle ausschließen möchte, das wäre besser, da ich normalerweise die meisten oder alle Eigenschaften der Klasse haben möchte), aber ich bin mir nicht sicher, wie (ich habe nie Nachdenken benutzt, aber ich bin es Raten, das ist wie). Außerdem sollte die Methode eine Liste beliebiger Klassen akzeptieren.

Irgendwelche cleveren Ideen, wie dies zu erreichen ist?

Antwort

19

Vielleicht so etwas?

var html = GetMyTable(people, x => x.LastName, x => x.FirstName); 

public static string GetMyTable<T>(IEnumerable<T> list,params Func<T,object>[] fxns) 
{ 

    StringBuilder sb = new StringBuilder(); 
    sb.Append("<TABLE>\n"); 
    foreach (var item in list) 
    { 
     sb.Append("<TR>\n"); 
     foreach(var fxn in fxns) 
     { 
      sb.Append("<TD>"); 
      sb.Append(fxn(item)); 
      sb.Append("</TD>"); 
     } 
     sb.Append("</TR>\n"); 
    } 
    sb.Append("</TABLE>"); 

    return sb.ToString(); 
} 

--Version 2.0--

public static string GetMyTable<T>(IEnumerable<T> list, params Expression<Func<T, object>>[] fxns) 
{ 

    StringBuilder sb = new StringBuilder(); 
    sb.Append("<TABLE>\n"); 

    sb.Append("<TR>\n"); 
    foreach (var fxn in fxns) 
    { 
     sb.Append("<TD>"); 
     sb.Append(GetName(fxn)); 
     sb.Append("</TD>"); 
    } 
    sb.Append("</TR> <!-- HEADER -->\n"); 


    foreach (var item in list) 
    { 
     sb.Append("<TR>\n"); 
     foreach (var fxn in fxns) 
     { 
      sb.Append("<TD>"); 
      sb.Append(fxn.Compile()(item)); 
      sb.Append("</TD>"); 
     } 
     sb.Append("</TR>\n"); 
    } 
    sb.Append("</TABLE>"); 

    return sb.ToString(); 
} 

static string GetName<T>(Expression<Func<T, object>> expr) 
{ 
    var member = expr.Body as MemberExpression; 
    if (member != null) 
     return GetName2(member); 

    var unary = expr.Body as UnaryExpression; 
    if (unary != null) 
     return GetName2((MemberExpression)unary.Operand); 

    return "?+?"; 
} 

static string GetName2(MemberExpression member) 
{ 
    var fieldInfo = member.Member as FieldInfo; 
    if (fieldInfo != null) 
    { 
     var d = fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute; 
     if (d != null) return d.Description; 
     return fieldInfo.Name; 
    } 

    var propertInfo = member.Member as PropertyInfo; 
    if (propertInfo != null) 
    { 
     var d = propertInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute; 
     if (d != null) return d.Description; 
     return propertInfo.Name; 
    } 

    return "?-?"; 
} 

PS: Aufruf fxn.Compile() wiederholt Leistungskiller in einer engen Schleife sein kann. Es kann besser sein, es in einem Wörterbuch zu speichern.

+0

Was passiert, wenn Sie beispielsweise versuchen, einen int und einen string auszuwählen? Wird "P" zu "Objekt", oder wird es nicht kompiliert? –

+0

@TimS. Danke, ich habe die Antwort aktualisiert. –

+0

Können Sie erklären, was "fxn (item)" gerade macht? – birdus

3

Hier sind zwei Ansätze, eine mit Reflexion:

public static string GetMyTable(IEnumerable list, params string[] columns) 
{ 
    var sb = new StringBuilder(); 
    foreach (var item in list) 
    { 
     //todo this should actually make an HTML table, not just get the properties requested 
     foreach (var column in columns) 
      sb.Append(item.GetType().GetProperty(column).GetValue(item, null)); 
    } 
    return sb.ToString(); 
} 
//used like 
string HTML = GetMyTable(people, "FirstName", "LastName"); 

Oder mit Lambda-Ausdrücke:

public static string GetMyTable<T>(IEnumerable<T> list, params Func<T, object>[] columns) 
{ 
    var sb = new StringBuilder(); 
    foreach (var item in list) 
    { 
     //todo this should actually make an HTML table, not just get the properties requested 
     foreach (var column in columns) 
      sb.Append(column(item)); 
    } 
    return sb.ToString(); 
} 
//used like 
string HTML = GetMyTable(people, x => x.FirstName, x => x.LastName); 

Mit der Lambda-Ausdrücke, passiert, was ist Sie vorbei Methoden zum GetMyTable Verfahren jeweils zu erhalten Eigentum. Dies hat Vorteile gegenüber Reflektion wie starke Typisierung und wahrscheinlich Leistung.

+0

Danke für die Hilfe, Tim. Ich schätze es, mehrere Möglichkeiten zu sehen, dies zu tun. – birdus

6

Dies ist, was ich getan habe und es scheint gut zu funktionieren und nicht eine große Leistung zu schlagen.

public static string ToHtmlTable<T>(this List<T> listOfClassObjects) 
    { 
     var ret = string.Empty; 

     return listOfClassObjects == null || !listOfClassObjects.Any() 
      ? ret 
      : "<table>" + 
       listOfClassObjects.First().GetType().GetProperties().Select(p => p.Name).ToList().ToColumnHeaders() + 
       listOfClassObjects.Aggregate(ret, (current, t) => current + t.ToHtmlTableRow()) + 
       "</table>"; 
    } 

    public static string ToColumnHeaders<T>(this List<T> listOfProperties) 
    { 
     var ret = string.Empty; 

     return listOfProperties == null || !listOfProperties.Any() 
      ? ret 
      : "<tr>" + 
       listOfProperties.Aggregate(ret, 
        (current, propValue) => 
         current + 
         ("<th style='font-size: 11pt; font-weight: bold; border: 1pt solid black'>" + 
         (Convert.ToString(propValue).Length <= 100 
          ? Convert.ToString(propValue) 
          : Convert.ToString(propValue).Substring(0, 100)) + "..." + "</th>")) + 
       "</tr>"; 
    } 

    public static string ToHtmlTableRow<T>(this T classObject) 
    { 
     var ret = string.Empty; 

     return classObject == null 
      ? ret 
      : "<tr>" + 
       classObject.GetType() 
        .GetProperties() 
        .Aggregate(ret, 
         (current, prop) => 
          current + ("<td style='font-size: 11pt; font-weight: normal; border: 1pt solid black'>" + 
            (Convert.ToString(prop.GetValue(classObject, null)).Length <= 100 
             ? Convert.ToString(prop.GetValue(classObject, null)) 
             : Convert.ToString(prop.GetValue(classObject, null)).Substring(0, 100) + 
              "...") + 
            "</td>")) + "</tr>"; 
    } 

es passieren benutzen Sie einfach die ToHtmlTable() eine Liste Beispiel:

Liste Dokumente = GetMyListOfDocuments(); var table = Dokumente.ToHtmlTable();

Verwandte Themen