Following code gives a red squigly under "emp.(col.ColummnName)". Error is "identifier expected"
foreach (DataColumn col in dt.Columns)
{
emp.(col.ColumnName) = row[(col.ColumnName)];
}
emp is a custom class with property names which correspond to column names in dataTable dt.
I suspect that I have to construct the expression differently so that I can refer to a property of class emp with results of a method call (col.ColumnName).
Any ideas will be appreciated.
==========================
Final Answer with working function code;
public void rowToObject(ref DataRow dr, ref object myObj)
{
foreach (DataColumn dc in dr.Table.Columns)
{
string colName = dc.ColumnName;
object colValue = dr[colName];
if (object.ReferenceEquals(colValue, DBNull.Value))
{
colValue = null;
}
PropertyInfo pi = myObj.GetType().GetProperty(colName);
if (pi != null && colValue != null)
{
Type propType = null;
Type nullableType = Nullable.GetUnderlyingType(pi.PropertyType);
if (nullableType != null)
{
propType = nullableType;
}
else
{
propType = pi.PropertyType;
}
if (object.ReferenceEquals(propType, colValue.GetType()))
{
pi.SetValue(myObj, colValue, null);
}
}
}
}
This syntax is not supported, the property name must be known at compile time. You can use reflection instead:
foreach (DataColumn col in dt.Columns)
{
PropertyInfo prop = emp.GetType().GetProperty(col.ColumnName);
prop.SetValue(emp, row[col.ColumnName], null);
}
This dynamic access of class properties is really beneficial, but it's not as easy to implement as you are hoping for.
You need to look into Reflection... with this library, you can dynamically make and fill your classes, but it takes some reading and trial/error.
Here is a couple links that discuss your situation; however, you may want to look up a Reflection 101 tuturial first.:
http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx
Can C# Attributes access the Target Class?
.
.
Please vote if helpful
I'm not aware that you can do it in way that you're trying to do it. What you're looking for is reflection and you can find an example how it works in this post:
How to loop through all the properties of a class?
Related
I am trying to use generic list as cast of the object. i have seen related questions and tried but didn't get, what i expected.
In the below code i am setting the value to the main response.
Here is code:
Type type = Type.GetType("className, AssemblyName"); <br/>
var z = typeof(List<>).MakeGenericType(type);
foreach (var key in abc.Keys)
{
var value = abc[key];
foreach (var property in ((List<z>)output.Response)[0].GetType().GetProperties().Where(p => p.CanRead && p.GetMethod.IsPublic).)
{
if(property.Name == ((List<Document>)value)[0].GetType().Name)
{
PropertyInfo propertyInfo = ((List<Policy>)output.Response)[0].GetType().GetProperty(property.Name);
propertyInfo.SetValue(((List<Policy>)output.Response)[0], ((List<Document>)value));
}
}
}
while accessing z in list. i am unable to do that. I have stuck from past few hour.Please help me out.
Thanks in Advance!
I am getting the exception mentioned in the title at the line of code
values[i] = Props[i].GetValue(item, null);
and I am not sure what is causing this. Any help would be appreciated.
public static DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
dataTable.Columns.Add(prop.Name, type);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
If this line is throwing the exception
values[i] = Props[i].GetValue(item, null);
...then it means you have a property that requires a parameter. In c#, the only type of property that takes a parameter is an indexer. My guess is you should just exclude the indexer from the loop.
See this question which tells you how to detect an indexer.
You can probably fix this by changing one line. Change this...
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
...to this....
PropertyInfo[] Props = typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetIndexParameters == null))
.ToArray();
The issue was actually in the data that I passed into the method(a list of strings). It appeared that the GetValue() method was looking for an object. I created a class with a string property and changed my list type that was being passed in to the class and set the property in the class to the string that I was passing to the list in my foreach loop. Sorry if this doesn't make sense just trying to explain how I solved this, but the problem probably could have been solved a number of ways. Thanks, all.
Currently, I am using Reflection and want to know if any other way to achieve the same.
foreach (var propertyInfo in MyObject.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
if (propertyInfo.Name.Equals(fieldName))
{
propertyInfo.SetValue(MyObject, "Some value", null);
break;
}
}
}
You can use a quicker version of reflection than what you have (the loop is not necessary):
var propertyInfo = MyObject.GetType().GetProperty(fieldName);
if (propertyInfo != null && propertyInfo.CanRead)
propertyInfo.SetValue(MyObject, "Some value", null);
Beyond reflection, I believe you can emit IL code directly -- take a look at "FastMember" (although I am not sure if Silverlight can support this approach).
If all you have is a string of the property name then I don't know any better way then reflection but looping on the posted code is not efficient.
HashSet<String> properties = new HashSet<String>();
// add the properties
foreach (var propertyInfo in MyObject.GetType().GetProperties())
{
if (propertyInfo.CanRead)
{
if (properties.Contains(propertyInfo.Name))
{
propertyInfo.SetValue(MyObject, "Some value", null);
}
}
}
I have a C# method that I need to pass various lists into. The type of lists will be different very often. The method itself is in a different dll and cannot know the class objects contained in the lists (no references, no using statements). The method needs to read each of the members of each of the items in a list and build and return a string based off of that.
My question is how can get the metadata for for these various objects at compiletime / runtime? Will reflection do that?
Also, once I get the metadata, how do i use it to actually use the variables?
Thank you
EDIT: currently I am using it like the following:
public string GetData(List<User> list){
//...
List<RowData> rows = new List<RowData>();
foreach (User item in list)
{
RowData row = new RowData();
row.id = count++;
row.cell = new string[3];
row.cell[0] = item.ID.ToString();
row.cell[1] = item.name;
row.cell[2] = item.age.ToString();
rows.Add(row);
}
//...
return new JavaScriptSerializer().Serialize(rows.ToArray());
Right now this is very specific. I want to replace this with generics so I can pass items other than "User"
If the parameter (will call it list for discussion's sake) coming into the method is List<T> then you can do the following:
Type type = list.GetType().GetGenericArguments()[0];
If you just have a generic T class, then you can always just go with this:
Type typeParameterType = typeof(T);
.GetType() will get you a Type and you can get a lot of descriptions about the type.
You can also discover members of the instances you have using reflection
Please be precise with what you want more exactly ?
EDIT : Here is a way, try making it an extenstion method it would be better
public static List<RowData> ToDataTable<T>(IEnumerable<T> source)
{
System.Reflection.PropertyInfo[] properties = typeof(T).GetProperties();
List<RowData> rows = new List<JQGridRow>();
foreach (var item in source)
{
RowData row = new RowData();
row.cells = new string[properties.Length];
int i=0;
foreach (var prop in properties)
{
row.cells[i] = prop.GetValue(item, null);i++;
}
rows.Add(row);
}
return rows;
}
Yes, you can use reflection to obtain the type of an object at runtime.
Simple call to object.GetType() will give you the type of this instance.
What you do with this information is up to you.
Maybe something like this?
public string GetData<T>(IEnumerable<T> list, Func<T, RowData> fillRow)
{
List<RowData> rows = new List<JQGridRow>();
foreach (User item in list)
{
RowData row = new RowData();
row.id = count++;
fillRow(row);
rows.Add(row);
}
//...
return new JavaScriptSerializer().Serialize(rows.ToArray());
}
And use it like
string s = GetData(users, row =>
{
row.cell = new string[3];
row.cell[0] = item.ID.ToString();
row.cell[1] = item.name;
row.cell[2] = item.age.ToString();
});
This might work if you treat them all as objects, using the intrinsic ToString() method for your string building.
I'm working in a project to get some information about Issuers. In MainWindow activity I have this line of code:
builder.AddCustomAttributes(typeof(IssuerActivity), new DesignerAttribute(typeof(IssuerDesigner)));
So I have a IssuerDesigner that I put in a listbox all of the Issuers in his contructor method and I save in an Issuer [] all of these.
Now, when I execute this rehosted workflow, I need to send this Issuer[] to IssuerActivity to analized in a foreach task everyone of them...
The question is: ¿What have I to do to for IssuerActivity gets Issuer[] that It's assigned in IssuerDesigner?
Your question is hard to follow but I beleive this is what you are looking for. You will have to use Reflection on your object to be able to grab the Attribute Values. It should be something like this.
MemberInfo[] members = builder.GetType().GetProperties();
foreach (MemberInfo m in members)
{
if (m.MemberType == MemberTypes.Property)
{
PropertyInfo p = m as PropertyInfo;
object[] attribs = p.GetCustomAttributes(false);
foreach (object attr in attribs)
{
IssuerDesigner d = attr as IssuerDesigner;
if (d != null)
{
foreach(object obj in d.Issuer)
{
DoSomething(obj);
}
}
}
}
}