How to remove column headers in dataTable? - c#

I have generic list and I'm converting that to DataTable
Then I'm generating columns with the properties of the list and adding rows to it, Now I want to remove the column headers fro the table
This is my code for Converting List To DataTable
public class ListtoDataTableConverter
{
public DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
}
The result for the above code is
Name Age
---------------------------------
A 22
B 23
Now I want to have the output without the Name and Age.
How can I remove them

No real way of "removing" column headers from a table - it is a table after all. But why not just tell epplus to suppress the outputting of the header row with .LoadFromDataTable(dtdata, false) - note the false as the second paramter `PrintHeaders'.
[TestMethod]
public void ListToDataTableConverter()
{
//Use a func for demonstrative purposes
Func<List<NameAgeObject>, DataTable> ToDataTable = (items) =>
{
DataTable dataTable = new DataTable(typeof(NameAgeObject).Name);
//Get all the properties
PropertyInfo[] Props = typeof(NameAgeObject).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (NameAgeObject item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
};
var itemlist = new List<NameAgeObject>
{
new NameAgeObject {Name = "A", Age = 22},
new NameAgeObject {Name = "B", Age = 23},
new NameAgeObject {Name = "C", Age = 24},
new NameAgeObject {Name = "D", Age = 25},
new NameAgeObject {Name = "E", Age = 26},
};
var dtdata = ToDataTable(itemlist);
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var package = new ExcelPackage(existingFile))
{
var ws = package.Workbook.Worksheets.Add("Sheet1");
ws.Cells[1, 1].LoadFromDataTable(dtdata, false);
package.Save();
}
}
If it is a very big table you might see a performance problem with LoadFromDataTable in which case you can manually write to the worksheet by hitting the individual cells in excel. Here you ap the datatable by row/column and simply skip any writing of column info.

Related

C#: Bind Dictionary<string, List<string>> to DataTable

I have one dictionary Like
Dictionary<string, List<string>> first=new Dictionary<string, List<string>>();
I want to bind this dictionary to data table such that data table ColumnName should be key of the dictionary and respective columns should contain their dictionary values.
What I tried:
Dictionary<string, List<string>> some= new Dictionary<string, List<string>>();
System.Data.DataTable dt = new System.Data.DataTable();
foreach (var entry in some)
{
if (entry.Value.Count > 0)
{
dt.Columns.Add(entry.Key);
//entry.Value.count is not same for all entry.Key
foreach (var value in entry.Value)
{
DataRow row = dt.NewRow();
row[entry.Key] = value;
dt.Rows.Add(row);
}
}
}
Surely I know, above code is having some errors to achieve following result
DesirrdResultImage
any suggestions?
Here's a possible solution (note that I don't think this is the best way to do this, but I hope it'll help guide you):
Dictionary<string, List<string>> some = new Dictionary<string, List<string>>
{
{ "Key1", new List<string>
{
"Val1_1",
"Val2_1",
"Val3_1"
}
},
{ "Key2", new List<string>
{
"Val1_2",
"Val2_2",
"Val3_2"
}
}
};
DataTable dt = new DataTable();
var keys = some.Keys;
// Add all the columns from the beginning
dt.Columns.AddRange(keys.Select(key => new DataColumn(key)).ToArray());
// Get the rows number using the Max count of the lists (assuming the length of the lists might change, otherwise just use some.Values[0].Count)
int rowsNumber = some.Values.Max(s => s.Count);
for (int i = 0; i < rowsNumber; i++)
{
var row = dt.NewRow();
// Set all the values depending on the keys
foreach (var key in keys)
{
if (some[key].count <= i)
break;
row[key] = some[key][i];
}
dt.Rows.Add(row);
}
dataGridView1.DataSource = dt;
The result is:
Check if No row or less than Values than add Value to New row
else
Add value to existing row
DataTable dt = new DataTable();
int i = 0;
foreach (var entry in some)
{
if (entry.Value.Count > 0)
{
dt.Columns.Add(entry.Key);
DataRow row;
//entry.Value.count is not same for all entry.Key
foreach (var value in entry.Value)
{
int ValueCount = entry.Value.Count();
if (dt.Rows.Count <= ValueCount)
{
row = dt.NewRow();
row[entry.Key] = value;
dt.Rows.Add(row);
}
else
{
row = dt.Rows[i];
row[entry.Key] = value;
i++;
}
}
}
}

Row already belongs to another table error when trying to add rows?

I tried this solution below:
This Row already belongs to another table error when trying to add rows?
I have a Datatable that contains 597 Columns and 20 Rows and are trying to export the data to excel. However, Excel has a maximum column count 256 and so I need to divide the source data into 3 datatables to make the export work.
Below is the code I have written.
var dtmasterdata = data.Tables[name];
for (int j = 1; j < datatableNumberCount; j++)
{
DataTable dt2 = new DataTable();
dt2.TableName = "Master_" + j;
dt2 = dtmasterdata.Copy();
foreach (DataColumn col in dtmasterdata.Columns)
{
DataColumn dtcol = new DataColumn();
dtcol = col;
dt2.Columns.Add(dtcol.ColumnName, dtcol.DataType);
}
for (int k = 0; k < dtmasterdata.Rows.Count; k++)
{
DataRow dr = dt2.NewRow();
dr = dtmasterdata.Rows[k];
dt2.ImportRow(dtmasterdata.Rows[k]);
//dt2.Rows.Add(dr.ItemArray);
}
After that I need to delete few columns like below and I want to create 3 datatables
foreach (DataColumn col in dtmasterdata.Columns)
{
if (j == 1)
{
// condition 1
if (col.Ordinal >= 255)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 2)
{
// condition 2.
if (col.Ordinal < 255 || col.Ordinal >= 510)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 3)
{
// condition 3.
if (col.Ordinal <= 510 || col.Ordinal >= 765)
{
dt2.Columns.Add(col);
}
}
}
int worksheetNumber = 1;
string worksheetNameWithNumber = "Master Data";
if (worksheetNumber > 1)
worksheetNameWithNumber = String.Format("{0}_{1}", ws1, worksheetNumber.ToString());
Infragistics.Excel.Worksheet worksheet = wb.Worksheets.Add(worksheetNameWithNumber);
Infragistics.WebUI.UltraWebGrid.UltraWebGrid masterData1 = new Infragistics.WebUI.UltraWebGrid.UltraWebGrid("masterDataGrid");
masterData1.Browser = Infragistics.WebUI.UltraWebGrid.BrowserLevel.UpLevel;
masterData1.DataSource = dt2;
masterData1.DataMember = "Master_" + j;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Bold = true;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.HeaderStyleDefault.Font.Size = FontUnit.Parse("10px");
masterData1.DisplayLayout.HeaderStyleDefault.BackColor = System.Drawing.Color.LightGray;
masterData1.DisplayLayout.RowStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.RowStyleDefault.Font.Size = FontUnit.Parse("10px");
Infragistics.WebUI.UltraWebGrid.UltraGridBand masterBand1 = new Infragistics.WebUI.UltraWebGrid.UltraGridBand();
masterData1.Bands.Add(masterBand1);
dgResults.Controls.Add(masterData1);
masterData1.DataBind();
wb.ActiveWorksheet = worksheet;
this.ugWebGridExporter.Export(masterData1, worksheet);
worksheetNumber++;
Your error is because you are trying to add a column to a datatable that already belongs to your source datatable.
dt2.Columns.Add(col);
You can't just iterate through the columns of a datatable and add them to another.
I've a solution to this, which involves cloning the source data and removing what you don't need.
1st, make 3 clones of the datatables you need. Below is an example with me creating my own source table with 596 columns. Notice that clone only takes the data table structure, no data!
var source597ColsTable = new DataTable("Source");
for (var i = 0; i <= 596; i++)
{
source597ColsTable.Columns.Add(new DataColumn("Column" + i , typeof(string)));
}
DataRow newRow = source597ColsTable.NewRow();
source597ColsTable.Rows.Add(newRow);
var cols0To199Table = source597ColsTable.Clone();
var cols200To399Table = source597ColsTable.Clone();
var cols400To596Table = source597ColsTable.Clone();
Next copy all the rows from the source table into the clones. The below is a simple function to do so.
private DataTable CopyRowsFromSource(DataTable sourceTable, DataTable destinationTable)
{
foreach (DataRow row in sourceTable.Rows)
{
destinationTable.Rows.Add(row.ItemArray);
}
return destinationTable;
}
Then call this function for each of your tables.
cols0To199Table = CopyRowsFromSource(source597ColsTable, cols0To199Table);
cols200To399Table = CopyRowsFromSource(source597ColsTable, cols200To399Table);
cols400To596Table = CopyRowsFromSource(source597ColsTable, cols400To596Table);
Finally, remove all the columns from the datatables to give you your split.
private DataTable RemoveColumns(DataTable table, int startCol, int endCol)
{
var colsToRemove = new List<DataColumn>();
for (var colCount = startCol; colCount <= endCol; colCount++)
{
colsToRemove.Add(table.Columns[colCount]);
}
foreach (DataColumn col in colsToRemove)
{
table.Columns.Remove(col);
}
return table;
}
Then call.. again for each cloned table.
cols0To199Table = RemoveColumns(cols0To199Table, 200, 596);
cols200To399Table = RemoveColumns(cols200To399Table, 0, 199);
cols200To399Table = RemoveColumns(cols200To399Table, 200, 396);
cols400To596Table = RemoveColumns(cols400To596Table, 0, 399);
After running this, you will have 3 datatables, columns 0-199, 200-399 and 400-596.
Hope that helps.
I am not sure to have really understood all of your code, but to copy a subset of columns to another datatable there is a very simple method in the DataView class named ToTable where you can list the columns you want in the new table. As added bonus, this method copies also the data in the 20 rows of your original table.
So the only difficult is to list these columns to the method.
You can proceed in this way using linq over the DataColumn collection
string[] firstCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] secondCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(255)
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] thirdCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(510)
.Select(x => x.ColumnName).ToArray();
DataTable t1 = dtmasterdata.DefaultView.ToTable("Master_1", false, firstCols);
DataTable t2 = dtmasterdata.DefaultView.ToTable("Master_2", false, secondCols);
DataTable t3 = dtmasterdata.DefaultView.ToTable("Master_3", false, thirdCols);

linq cast error

I'm trying to get some data from DataTable using Linq, but it gives me following error:
Specified cast is not valid.
First of all, i'm using this to paste copied cells from excel to datagridview
private void btnExcel_Click(object sender, EventArgs e)
{
dataGridView1.Columns.Clear();
dataGridView1.Columns.Add("Column1", "Column1");
dataGridView1.Columns.Add("Column2", "Column2");
dataGridView1.Columns.Add("Column3", "Column3");
dataGridView1.Columns.Add("Column4", "Column4");
dataGridView1.Columns.Add("Column5", "Column5");
dataGridView1.Columns.Add("Column6", "Column6");
dataGridView1.Columns.Add("Column7", "Column7");
dataGridView1.Columns.Add("Column8", "Column8");
dataGridView1.Columns.Add("Column9", "Column9");
dataGridView1.Columns.Add("Column10", "Column10");
dataGridView1.Columns.Add("Column11", "Column11");
dataGridView1.Columns.Add("Column12", "Column12");
dataGridView1.Columns.Add("Column13", "Column13");
DataObject o = (DataObject)Clipboard.GetDataObject();
if (o.GetDataPresent(DataFormats.UnicodeText))
{
if (dataGridView1.RowCount > 0)
dataGridView1.Rows.Clear();
string[] pastedRows = Regex.Split(o.GetData(DataFormats.UnicodeText).ToString().TrimEnd("\r\n".ToCharArray()), "\r\n");
int j = 0;
foreach (string pastedRow in pastedRows)
{
string[] pastedRowCells = pastedRow.Split(new char[] { '\t' });
dataGridView1.Rows.Add();
int myRowIndex = dataGridView1.Rows.Count - 1;
using (DataGridViewRow myDataGridViewRow = dataGridView1.Rows[j])
{
for (int i = 0; i < pastedRowCells.Length; i++)
myDataGridViewRow.Cells[i].Value = pastedRowCells[i];
this.dataGridView1.AutoResizeColumns();
}
j++;
}
}
}
Then I'm using this method to convert datagridview to DataTable
private DataTable GetDataTableFromDGV(DataGridView dgv)
{
var dt = new DataTable();
foreach (DataGridViewColumn column in dgv.Columns)
{
if (column.Visible)
{
// You could potentially name the column based on the DGV column name (beware of dupes)
// or assign a type based on the data type of the data bound to this DGV column.
dt.Columns.Add();
}
}
object[] cellValues = new object[dgv.Columns.Count];
foreach (DataGridViewRow row in dgv.Rows)
{
for (int i = 0; i < row.Cells.Count; i++)
{
cellValues[i] = row.Cells[i].Value;
}
dt.Rows.Add(cellValues);
}
return dt;
}
after that using this linq query to get data and display it to datagridview2
DataTable dt = GetDataTableFromDGV(dataGridView1);
//foreach (DataColumn c in dt.Columns)
//{
// MessageBox.Show(c.ColumnName);
//}
var groupedData = from b in dt.AsEnumerable()
group b by b.Field<int>("Column2") into g
select new
{
column2 = g.Key,
column13 = g.Sum(x => x.Field<decimal>("Column13"))
};
foreach (var result in groupedData)
{
dataGridView2.Rows.Add(result);
}
It throws a " Specified cast is not valid."
Basically what I want is shows on picture below:
pic
You never assign a type to any of the DataColumns that you show, so they will have a default data type of string, and calling Field<int> or Field<decimal> will throw an invalid cast exception.
Either assign the appropriate types to the columns when creating the data table or parse the string values:
var groupedData = from b in dt.AsEnumerable()
group b by int.Parse(b.Field<string>("Column2")) into g
select new
{
column2 = g.Key,
column13 = g.Sum(x => decimal.Parse(x.Field<string>("Column13")))
};

How to convert a LINQ query result to a DataTable dynamically?

How to convert a LINQ query result to a DataTable dynamically?
There are solutions where you create another class and specify the column names, but I want the flexibility to change the LINQ structure like column names, column quantities, and have a DataTable generated with the columns names automatically.
Thanks
I've included an extension method that I use with SqlBulkCopy that should do the job, but I'd like to ask why you want to this conversion. There are a very limited number of cases (SqlBulkCopy being one) where a list of objects can't do everything a datatable can. You can use them as binding sources for most controls ... just curious.
public static DataTable toDataTable<T>(this IEnumerable<T> value, List<string> exclusionList)
where T : class
{
var dataTable = new DataTable();
var type = typeof(T);
var properties = type.GetProperties().Where(x => !exclusionList.Contains(x.Name)).ToList();
foreach (var propertyInfo in properties)
{
var propertyType = propertyInfo.PropertyType;
if (!propertyType.IsScalar())
continue;
var nullableType = Nullable.GetUnderlyingType(propertyType);
propertyType = nullableType ?? propertyType;
var dataColumn = new DataColumn(propertyInfo.Name, propertyType);
if (nullableType != null)
dataColumn.AllowDBNull = true;
dataTable.Columns.Add(dataColumn);
}
foreach (var row in value)
{
var dataRow = dataTable.NewRow();
foreach (var property in properties)
{
var safeValue = property.GetValue(row, null) ?? DBNull.Value;
dataRow[property.Name] = safeValue;
}
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Look into the MoreLinq Nuget package. It has a function ToDataTable()
var LinqResults = from ......;
DataTable dt_Results = LinqResults.ToDataTable();
https://code.google.com/p/morelinq/
It has other VERY useful functions as well:
https://code.google.com/p/morelinq/wiki/OperatorsOverview
They key is to use the LINQ query result as its Implemented IList interface.
If you receive the result as a parameter on a method as an IList object, you can access its columns and rows, this way:
var props = item.GetType().GetProperties();
Refer to this example, it's a small class which please note the it just abstracts the creation of the DataTable, and there is a static method inside called "LINQToDataTable" which you should use.
Step 1, create a class called "GridHelper" (uses System.Data for DataTable structure)
public class GridHelper
{
private DataTable baseDt;
public GridHelper(string tableName)
{
baseDt = new DataTable(tableName);
}
public DataTable getDataTable()
{
return baseDt;
}
public object[,] getObjToFill()
{
object[,] obj = new object[baseDt.Columns.Count, 2];
for (int i = 0; i < baseDt.Columns.Count; i++)
{
obj[i, 0] = baseDt.Columns[i].ColumnName;
}
return obj;
}
public void addColumn(string colName, Type valueType)
{
baseDt.Columns.Add(colName, valueType);
}
public void addRow(object[,] values)
{
DataRow newRow = baseDt.NewRow();
for (int i = 0; i < values.Length / 2; i++)
{
bool colFound = false;
for (int j = 0; j < baseDt.Columns.Count; j++)
{
if (baseDt.Columns[j].ColumnName == values[i, 0].ToString())
{
colFound = true;
break;
}
}
if (colFound == false)
{
throw new Exception("The column " + values[i, 0].ToString() + " has not been added yet.");
}
newRow[values[i, 0].ToString()] = values[i, 1];
}
baseDt.Rows.Add(newRow);
}
public static DataTable LINQToDataTable<T>(T objToList) where T : System.Collections.IList
{
GridHelper ghResult = new GridHelper("Report");
foreach (Object item in objToList)
{
var props = item.GetType().GetProperties();
foreach (var prop in props)
{
ghResult.addColumn(prop.Name, typeof(string));
//prop.Name
//prop.GetValue(item)
}
break;
}
object[,] obj = ghResult.getObjToFill();
foreach (Object item in objToList)
{
var props = item.GetType().GetProperties();
int index = 0;
foreach (var prop in props)
{
//ReportValue(prop.Name, prop.GetValue(item, null));
//prop.Name
obj[index, 1] = prop.GetValue(item);
index++;
}
ghResult.addRow(obj);
}
return ghResult.getDataTable();
}
}
Usage:
var listaReporte =
(from t in dbContext.TablaPruebas
select new
{
Name = t.name,
Score = t.score
}
) .ToList();
DataTable dt = Library.GridHelper.LINQToDataTable(listaReporte);
And that is, use your DataTable as you wish, on a GridView or DataGridView

c# foreach (property in object)... Is there a simple way of doing this?

I have a class containing several properties (all are strings if it makes any difference).
I also have a list, which contains many different instances of the class.
While creating some unit tests for my classes I decided I wanted to loop through each object in the list and then loop through each property of that object...
I thought doing this would be as simple as...
foreach (Object obj in theList)
{
foreach (Property theProperties in obj)
{
do some stufff!!;
}
}
But this didnt work! :(
I get this error...
"foreach statement cannot operate on variables of type 'Application.Object' because 'Application.Object' does not contain a public definition for 'GetEnumerator'"
Does anyone know of a way of doing this without tons of ifs and loops or without getting into anything too complex?
Give this a try:
foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
// do stuff here
}
Also please note that Type.GetProperties() has an overload which accepts a set of binding flags so you can filter out properties on a different criteria like accessibility level, see MSDN for more details: Type.GetProperties Method (BindingFlags) Last but not least don't forget to add the "system.Reflection" assembly reference.
For instance to resolve all public properties:
foreach (var propertyInfo in obj.GetType()
.GetProperties(
BindingFlags.Public
| BindingFlags.Instance))
{
// do stuff here
}
Please let me know whether this works as expected.
You can loop through all non-indexed properties of an object like this:
var s = new MyObject();
foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) {
Console.WriteLine(p.GetValue(s, null));
}
Since GetProperties() returns indexers as well as simple properties, you need an additional filter before calling GetValue to know that it is safe to pass null as the second parameter.
You may need to modify the filter further in order to weed out write-only and otherwise inaccessible properties.
Your'e almost there, you just need to get the properties from the type, rather than expect the properties to be accessible in the form of a collection or property bag:
var property in obj.GetType().GetProperties()
From there you can access like so:
property.Name
property.GetValue(obj, null)
With GetValue the second parameter will allow you to specify index values, which will work with properties returning collections - since a string is a collection of chars, you can also specify an index to return a character if needs be.
Sure, no problem:
foreach(object item in sequence)
{
if (item == null) continue;
foreach(PropertyInfo property in item.GetType().GetProperties())
{
// do something with the property
}
}
Use Reflection to do this
SomeClass A = SomeClass(...)
PropertyInfo[] properties = A.GetType().GetProperties();
I looked for the answer to a similar question on this page, I wrote the answers to several similar questions that may help people who enter this page.
Class List
List < T > class represents the list of objects which can be accessed by index. It comes under the System.Collection.Generic namespace. List class can be used to create a collection of different types like integers, strings etc. List class also provides the methods to search, sort, and manipulate lists.
Class with property:
class TestClss
{
public string id { set; get; }
public string cell1 { set; get; }
public string cell2 { set; get; }
}
var MyArray = new List<TestClss> {
new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
Console.WriteLine("Row Start");
foreach (PropertyInfo property in Item.GetType().GetProperties())
{
var Key = property.Name;
var Value = property.GetValue(Item, null);
Console.WriteLine("{0}={1}", Key, Value);
}
}
OR, Class with field:
class TestClss
{
public string id = "";
public string cell1 = "";
public string cell2 = "";
}
var MyArray = new List<TestClss> {
new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
Console.WriteLine("Row Start");
foreach (var fieldInfo in Item.GetType().GetFields())
{
var Key = fieldInfo.Name;
var Value = fieldInfo.GetValue(Item);
}
}
OR, List of objects (without same cells):
var MyArray = new List<object> {
new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data", anotherCell = "" }
};
foreach (object Item in MyArray)
{
Console.WriteLine("Row Start");
foreach (var props in Item.GetType().GetProperties())
{
var Key = props.Name;
var Value = props.GetMethod.Invoke(Item, null).ToString();
Console.WriteLine("{0}={1}", Key, Value);
}
}
OR, List of objects (It must have the same cells):
var MyArray = new[] {
new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
Console.WriteLine("Row Start");
foreach (var props in Item.GetType().GetProperties())
{
var Key = props.Name;
var Value = props.GetMethod.Invoke(Item, null).ToString();
Console.WriteLine("{0}={1}", Key, Value);
}
}
OR, List of objects (with key):
var MyArray = new {
row1 = new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
row2 = new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
row3 = new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
// using System.ComponentModel; for TypeDescriptor
foreach (PropertyDescriptor Item in TypeDescriptor.GetProperties(MyArray))
{
string Rowkey = Item.Name;
object RowValue = Item.GetValue(MyArray);
Console.WriteLine("Row key is: {0}", Rowkey);
foreach (var props in RowValue.GetType().GetProperties())
{
var Key = props.Name;
var Value = props.GetMethod.Invoke(RowValue, null).ToString();
Console.WriteLine("{0}={1}", Key, Value);
}
}
OR, List of Dictionary
var MyArray = new List<Dictionary<string, string>>() {
new Dictionary<string, string>() { { "id", "1" }, { "cell1", "cell 1 row 1 Data" }, { "cell2", "cell 2 row 1 Data" } },
new Dictionary<string, string>() { { "id", "2" }, { "cell1", "cell 1 row 2 Data" }, { "cell2", "cell 2 row 2 Data" } },
new Dictionary<string, string>() { { "id", "3" }, { "cell1", "cell 1 row 3 Data" }, { "cell2", "cell 2 row 3 Data" } }
};
foreach (Dictionary<string, string> Item in MyArray)
{
Console.WriteLine("Row Start");
foreach (KeyValuePair<string, string> props in Item)
{
var Key = props.Key;
var Value = props.Value;
Console.WriteLine("{0}={1}", Key, Value);
}
}
Good luck..
A small word of caution, if "do some stuff" means updating the value of the actual property that you visit AND if there is a struct type property along the path from root object to the visited property, the change you made on the property will not be reflected on the root object.
A copy-paste solution (extension methods) mostly based on earlier responses to this question.
Also properly handles IDicitonary (ExpandoObject/dynamic) which is often needed when dealing with this reflected stuff.
Not recommended for use in tight loops and other hot paths. In those cases you're gonna need some caching/IL emit/expression tree compilation.
public static IEnumerable<(string Name, object Value)> GetProperties(this object src)
{
if (src is IDictionary<string, object> dictionary)
{
return dictionary.Select(x => (x.Key, x.Value));
}
return src.GetObjectProperties().Select(x => (x.Name, x.GetValue(src)));
}
public static IEnumerable<PropertyInfo> GetObjectProperties(this object src)
{
return src.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => !p.GetGetMethod().GetParameters().Any());
}
For me the solution was to change GetProperties() to GetRuntimeProperties().
static void EnumObject(ShareCollection obj)
{
foreach (PropertyInfo property in obj.GetType().GetRuntimeProperties())
{
property.GetValue(obj);
}
}
I couldn't get any of the above ways to work, but this worked. The username and password for DirectoryEntry are optional.
private List<string> getAnyDirectoryEntryPropertyValue(string userPrincipalName, string propertyToSearchFor)
{
List<string> returnValue = new List<string>();
try
{
int index = userPrincipalName.IndexOf("#");
string originatingServer = userPrincipalName.Remove(0, index + 1);
string path = "LDAP://" + originatingServer; //+ #"/" + distinguishedName;
DirectoryEntry objRootDSE = new DirectoryEntry(path, PSUsername, PSPassword);
var objSearcher = new System.DirectoryServices.DirectorySearcher(objRootDSE);
objSearcher.Filter = string.Format("(&(UserPrincipalName={0}))", userPrincipalName);
SearchResultCollection properties = objSearcher.FindAll();
ResultPropertyValueCollection resPropertyCollection = properties[0].Properties[propertyToSearchFor];
foreach (string resProperty in resPropertyCollection)
{
returnValue.Add(resProperty);
}
}
catch (Exception ex)
{
returnValue.Add(ex.Message);
throw;
}
return returnValue;
}

Categories