Reputation: 77
I am trying to build a generic method for exporting a list to excel. An object will have attributes if the property should be printed. ie:
public class someObject {
public int DontPrint {get; set;}
[ExcelAttributes(PrintMe = true)]
public int PrintMe {get; set;}
[ExcelAttributes(PrintMe = true)]
public int PrintMeToo {get; set;}
}
I need a generic way to examine a List and return a printable object. something like the following.
public AppendCell<T>(List<T> list)
var obj = list[0];
PropertyInfo[] propertyInfos;
propertyInfos = obj.GetType().GetProperties(BindingFlags.Public |
BindingFlags.Instance);
foreach (T list1 in list)
{
foreach (PropertyInfo info in propertyInfos)
{
object[] customAttr = info.GetCustomAttributes(true);
// create cell with data
foreach (object o in customAttr)
{
ExcelAttributes ea = o as ExcelAttributes;
if (ea != null && ea.PrintMe ==true)
Cell c = new Cell(info.GetValue(list1,null).ToString())
}
}
}
return c;
}
So...I basically want to be able to examine a list of objects, get the printable properties based on the value of an attribute and print the values for the printable property.
if we create a list of someObject with the values
{DontPrint = 0, PrintMe = 1, PrintMeToo = 2}
{DontPrint = 0, PrintMe = 4, PrintMeToo = 5}
{DontPrint = 0, PrintMe = 3, PrintMeToo = 8}
I would expect to see:
1 2
4 5
3 8
Code similar to what is posted does what I need. Is there a more concise way to get a list of the properties that have the PrintMe attribute, then iterate through the list and act upon those properties?
Upvotes: 2
Views: 1047
Reputation: 2540
see code comments for details ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication5 {
internal class Program {
static void Main(string[] args) {
List<someObject> myList = new List<someObject>();
myList.Add(new someObject() {
DontPrint = 0,
PrintMe = 1,
PrintMeToo = 2
});
myList.Add(new someObject() {
DontPrint = 0,
PrintMe = 4,
PrintMeToo = 5
});
myList.Add(new someObject() {
DontPrint = 0,
PrintMe = 3,
PrintMeToo = 8
});
string[,] myPrintables = GetPrintables(myList);
System.Console.ReadKey();
}
public class someObject {
public int DontPrint {
get;
set;
}
[ExcelAttributes( true)]
public int PrintMe {
get;
set;
}
[ExcelAttributes(true)]
public int PrintMeToo {
get;
set;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <returns>string[,] - very easy to export to excel in array operation</returns>
public static string[,] GetPrintables<T>(System.Collections.Generic.IList<T> list) {
List<System.Reflection.PropertyInfo> discoveredProperties =
new List<System.Reflection.PropertyInfo>();
System.Type listType = typeof(T);
// first get the property infos (not on every iteration)
foreach (System.Reflection.PropertyInfo propertyInfo in listType.GetProperties(
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) {
// no indexers
if (propertyInfo.GetIndexParameters().Length == 0) {
ExcelAttributes[] attributes = propertyInfo.GetCustomAttributes(typeof(ExcelAttributes), true) as ExcelAttributes[];
// allowmultiple = false hence length e {0;1}
if (attributes != null && attributes.Length == 1) {
if (attributes[0].PrintMe) {
discoveredProperties.Add(propertyInfo);
}
}
}
}
int numberOfDiscoveredProperties = discoveredProperties.Count;
// can be instantiated only if there are discovered properties, but null may be returned
string[,] arrayItems = new string[list.Count, numberOfDiscoveredProperties];
// if we have any printables
if (numberOfDiscoveredProperties > 0) {
for (int iItem = 0; iItem < list.Count; iItem++) {
for (int iProperty = 0; iProperty < numberOfDiscoveredProperties; iProperty++) {
object value = discoveredProperties[iProperty].GetValue(list[iItem], null);
// value.ToString may not be ideal, perhaps also cache StringConverters
arrayItems[iItem, iProperty] = value != null ? value.ToString() : string.Empty;
}
}
}
return arrayItems;
}
}
[System.AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ExcelAttributes : System.Attribute {
// use readonly field
private readonly bool _PrintMe;
public ExcelAttributes(bool printMe) {
_PrintMe = printMe;
}
public bool PrintMe {
get {
return _PrintMe;
}
}
}
}
Upvotes: 0
Reputation: 56934
Isn't it a better idea to create an interface IPrintable
which has a member method which returns you a collection of printable properties ?
For instance, something like this:
interface IPrintable
{
ICollection<PrintProperties> GetPrintableProperties();
}
where the PrintProperties type consists for instance out of 2 members (a name & a value). ?
Then, you could just implement this interface to your classes for which you would like to have this behaviour.
But, if you just want to stick with your solution, and you want to have a shorter way to write this, you could perhaps take a look at LINQ. I believe something like this, should do the trick as well (not tested):
var printableProperties = obj.GetType().GetProperties().Where (pi => Attribute.IsDefined (pi, typeof(PrintableAttribute)).ToList();
Upvotes: 4