I created some code from an XSD-schema-file using CodeDOM:
XmlSchemaImporter importer = new XmlSchemaImporter(schemas);
CodeNamespace code = new CodeNamespace(targetNamespace);
XmlCodeExporter exporter = new XmlCodeExporter(code);
foreach (XmlSchemaElement element in schema.Elements.Values)
{
XmlTypeMapping mapping = importer.ImportTypeMapping(element.QualifiedName);
exporter.ExportTypeMapping(mapping);
}
Now within my post-processing I realized that this code will generate properties like this:
bool prop1Field;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public bool Prop1
{
get
{
return prop1Field;
}
set
{
prop1Field = value;
}
}
But I want the generator to simply produce fields instead. Is there a way to achieve this? I know xsd.exe also produces fields when using the /f-argument.
EDIT: Afterwards I want to replace those by auto-properties. To do so with the current approach I´d have to delete the backing-field from the property and all its occurences within the generated code. If CodeDOM however generates a public field in the first place all I had to do is to delete this field, create a new property with the same name using CodeSnippedTypeMember as shown in this answer. Thus I won´t need to search the codes for occurences of the private backing-field and replace them by calls to the property.
No, there´s no option to be set to allow this as it shouldn´t matter for consuming code if your attribute is a field or a property (assuming we don´t use reflection) and public fields are considered bad practice.
Anyway I found a way to achieve this by copying all the comments and attributes of the property to the private backing-field and make the field public. However remember that doing so is mostly a bad design-idea.
public void Process(CodeNamespace code, XmlSchema schema)
{
foreach (var type in code.Types.Cast<CodeTypeDeclaration>().Where(x => !x.IsEnum))
{
var result = new List<CodeMemberField>();
var properties = type.Members.OfType<CodeMemberProperty>().ToList();
foreach (var property in properties)
{
ReplacePropertyByField(type, property);
}
}
}
private static void ReplacePropertyByField(CodeTypeDeclaration type, CodeMemberProperty property)
{
var backingField = GetBackingField(property, type);
backingField.Comments.AddRange(property.Comments);
backingField.Attributes = property.Attributes;
backingField.CustomAttributes = property.CustomAttributes;
backingField.Name = property.Name;
type.Members.Remove(property);
}
private static CodeMemberField GetBackingField(CodeMemberProperty property, CodeTypeDeclaration type)
{
var getterExpression = ((CodeMethodReturnStatement)property.GetStatements[0]).Expression;
var backingFieldName = ((CodeFieldReferenceExpression)getterExpression).FieldName;
return type.Members.OfType<CodeMemberField>().Single(x => x.Name == backingFieldName);
}
Related
I am trying to use reflection for getting the property name declared and its value, I am able to get the declared property name using property info the main concern I am having is I want to get the value for the property and I don't know the object type so I cant cast directly.
I know we need to use item.GetValue(object) but here the object, I need to pass using reflection.
For example, if you see the below code
Class structure
public abstract class ObjectInputs{}
public class ValveInputs : ObjectInputs
{
public Conditions Conditions { get; set; } = new Conditions();
}
public class Conditions :IExportable
{
[CanExportAttribute]
public string north {get;set;}
}
Method
public void Append(Scenario scenario)
{
var scenarioInputs = (commonDomain.ObjectInputs)scenario.Inputs; // ObjectInputs is an abstract class
var exportableInputs = scenarioInputs.GetType().GetProperties().Where(x =\> typeof(IExportable).IsAssignableFrom(x.PropertyType)); // I extraced property having interface IExportable
var listOfExportableProperties = new ScenarioExtract();
foreach (var exportableInput in exportableInputs)
{
var allProperties = ((System.Reflection.TypeInfo)exportableInput.PropertyType).DeclaredProperties; // Got all the property details
var propertyHavingAttribute = allProperties.Where(x =\> x.CustomAttributes.Where(z =\> z.AttributeType == typeof(CanExportAttribute)).Any()).ToArray(); // Got the properties which i need to extract.
The issue is here, if i do this then its creating a new instance and the values of each properties are set to default. I want to cast the exportableInput to its type (I cant hard code the type casting) so that i can use the value below.
object destination = Activator.CreateInstance(scenarioInputs.GetType());
foreach (var item in propertyHavingAttribute)
{
var detail = new InputPropertyDetail { InputName = item.Name, InputValue = \*\*item.GetValue(destination).ToString() \*\*}; \*\*want to use value here\*\*
listOfExportableProperties.PropertyDetails.Add(detail);
}
}
spreadsheetBuilder.AppendComponenet(listOfExportableProperties);
}
If you're using Activator.CreateInstance, it will always create a new instance (as the name inplies) with default values. Instead you must use the value of the exportableInput property.
object destination = exportableInput.GetValue(scenarioInputs);
Then you can get the actual value of the exportable property of the instance with InputValue = item.GetValue(destination).ToString().
I am trying to do the following thing:
- From within a 1st method, I am going through a bunch of objects (of same type) and extracting pointers to specific properties into a list
- This list will then be fed to a another method elsewhere in my program at some point in time and has to modify all the properties (as per provided list) of the original objects
In other words, say we have the following class:
public class Something
{
public SomeFlag = False;
public Something()
{
}
}
Somewhere in the system, we have composed a related list of objects into List.
Now, we want to scan through this list and extract into "List< bool> flags" all the flags (by reference?):
List<bool> flags = new List<bool>();
foreach (var stuff in List<Something>)
{
flags.Add(stuff.SomeFlag);
}
Finally, somewhere else, I want to update these flags, but the update should affect the original object:
public static void SetStates(List<bool> myList)
{
// The flag should get set to true by reference in the original object
myList.SomeFlag = True;
}
Using actions could be one way to achive this:
public class Something
{
public bool SomeFlag { get; set; }
}
internal class Program
{
private static void Main()
{
var somethings = new[] {new Something(), new Something()};
var flags = new List<Action<bool>>();
// create your list of 'pointers'
foreach (var something in somethings)
{
flags.Add(x => something.SomeFlag = x);
}
// set them all to true
foreach (var action in flags)
{
action(true);
}
// check the results
foreach (var something in somethings)
{
Console.WriteLine(something.SomeFlag);
}
Console.WriteLine("press any key to exit...");
Console.ReadLine();
}
}
In C#, you cannot save a reference to a property value (like a pointer to the memory location where the value is stored). You only can save a reference to an object which contains this property value.
In your var list = new List<Something>(), you can store those references to the objects.
Note that it's impossible for value types though. If Something is a struct, not a class, then the list will contain copies of the objects, not the references to the objects. So the rest of my answer assumes we're talking about class Something.
You can define a property changing behavior and apply it using the list of the objects.
If you already know at compile time which properties and which values do you need, you can create a lambda and pass it around.
// Define the behavior and get the object list
Action<Something> setter = o => o.Someflag = true;
var objectList = new List<Something>();
// Call your processing method later on
SetProperties(objectList, setter);
void SetProperties<T>(List<T> objects, Action<T> setter)
{
objects.ForEach(setter);
}
If you don't know at compile which properties and which values you will need, then things get much more complicated. You will need to use Reflection to obtain the property descriptors and to set the values.
Here is a simplified example:
// Define the behavior and get the object list
var objectList = new List<Something>();
string propertyName = "SomeFlag";
PropertyInfo pi = typeof(Something).GetProperty(propertyName);
MethodInfo setter = pi.GetSetMethod();
object value = true;
// Call your processing method later on
SetProperties(objectList, setter, value);
void SetProperties<T>(List<T> objects, MethodInfo setter, object value)
{
var arguments = new object[] { value } ;
objects.ForEach(o => setter.Invoke(o, arguments));
}
i want to do a class constructor that takes a dicionary as parameter and initialize all the class variables that are listed as key in the dictionary, after of course a type conversion:
public class User
{
public int id;
public string username;
public string password;
public string email;
public int mana_fire;
public int mana_water;
public int mana_earth;
public int mana_life;
public int mana_death;
public User ()
{
}
public User(Dictionary<string,string> dataArray){
FieldInfo[] classVariablesInfoList = typeof(User).GetFields();
for(int i = 0; i < classVariablesInfoList.Length; i++)
{
if(dataArray.ContainsKey(classVariablesInfoList[i].Name)){
//missing code here :)
//need something like classVariable= dataArray["classVariablesInfolist[i].name"]; ?
}
}
}
}
but i can't find out how to do this!
Can you please help? :)
You can use the SetValue frunction from reflection:
FieldInfo f = classVariablesInfoList[i];
if (f.ReflectedType == typeof(int))
{
f.SetValue(this, Convert.ToInt32(dataArray[f.Name]));
}
else
{
f.SetValue(this, dataArray[classVariablesInfoList[i].Name]);
}
But it is a really uncommon way to do this with a dictionary. You should considder accessing the fields directly or add parameters to the constructor for any field. And fields should never be public - use properties instead.
The following will work if Convert.ChangeType() is able to handle the conversion. There are a lot of problems waiting to occur, for example handling numbers or dates where the string representation depends on the locale. I would really suggest to use usual typed constructor parameters or standard (de)serialization mechanism if possible. Or at least use a dictionary containing objects instead of strings to get rid of the conversion, again if possible.
public User(Dictionary<String, String> data)
{
var fields = typeof(User).GetFields();
foreach (field in fields)
{
if (data.ContainsKey(field.Name))
{
var value = Convert.ChangeType(data[field.Name], field.MemberType);
field.SetValue(this, value);
}
}
}
I would like to separate your problem into two parts.
1. Applying conversion
The FieldInfo type present a FieldType property that is the actual type of the field, using this Type we can use the non-generic ChangeType method of System.Convert, this method will be able convert some types to others. Luckily it support String to Int.
Usage:
Convert.ChangeType(OLD_VALUE, TARGET_TYPE);
2. Setting the field
The field info class has a SetValue method (FieldInfo.SetValue), it has two parameters, the first one is the current (ie. this) instance (or the instance you wish to change). the second is the new value you wish to set.
Putting it all together
[...]
var fieldInfo = classVariablesInfoList[i];
var name = fieldInfo.Name;
var targetType = fieldInfo.Type;
var value = Convert.ChangeType(dataArray[name], targetType);
classVariablesInfoList[i].SetValue(this, value);
After retrieving data from a database I find myself doing this to create a domain object from the data in a DataRow (in this case, a DVD):
DataRow drDvd = myDataTable.Rows[0];
Dvd myDvd = new Dvd();
myDvd.id = drDvd.Field<long>("id");
myDvd.title = drDvd.Field<string>("title");
myDvd.description = drDvd.Field<string>("description");
myDvd.releaseDate = drDvd.Field<DateTime>("releaseDate");
As I soon felt of course, I am doing this over and over in pseudo-code:
myDvd.field = drDvd.Field<field.type>(field.name);
And I wondered if I could get it into a loop, however I've never used reflection before. The code I tried is this:
Dvd aDvd = new Dvd();
Type t = aDvd.GetType();
FieldInfo[] fields = t.GetFields();
foreach (FieldInfo fi in fields)
{
fi.SetValue(aDvd, drDvd.Field<fi.FieldType>(fi.Name));
}
The problem is, as you may know, that the extension for the Field method of class DataRow does not accept a variable and needs to be explicitely filled in.
I am not that experienced in C# so I would like to pose the following two questions:
Is it good practice what I am trying to do?
How can I fill in the correct extension for Field<extension>(name)?
You'll need to get the method info for the generic method, and call invoke on it. This way you can pass in the generic type to it programmatically. I'm on my phone, but it should look something like this:
MethodInfo mField = typeof(Dvd).GetMethod("Field");
MethodInfo genericMethod = mField.MakeGenericMethod(new Type[] { fi.FieldType });
GenericMethod.Invoke(aDvd,new Object[]{fi.Name});
It is usually a bad practice to use reflection when it is not really necessary. Because reflection methods are checked at runtime rather than compile time, faulty code is harder to track, because the compiler can't check for errors.
If I were you, id have a look at the Entity Framework, because youre basically mapping database data to domain objects. http://msdn.microsoft.com/en-us/library/aa697427%28v=vs.80%29.aspx
This is one of the way of constructing and populating your domain object
DataRow drDvd = new DataRow();
Dvd aDvd = new Dvd();
Type type = typeof(Dvd);
foreach (FieldInfo fi in type.GetFields())
{
fi.SetValue(aDvd, drDvd[fi.Name]);
}
Your approach of using DataRow.Field may be round about. In you case, it is not applicable.
Alternatively you can think about using one of the Entity frameworks (NHibernate, Microsoft EF etc) in your application.
I would do a custom attribute. In doing an attribute you are stuck with your field name being the same as the database. I currently use this in my current applications and it works great. It is very similar to Entity SQL.
public class SqlMetaAttribute : Attribute
{
public string ColumnName { get; set; }
}
Then you have your class like this
public class Person
{
[SqlMeta(ColumnName = "First_Name")]
publice string FirstName { get; set; }
[SqlMeta(ColumnName = "Last_Name")]
publice string LastName { get; set; }
}
You would then have a helper class with the same kind of functions. In this case I am assuming the outside caller is looping through the datatable. Making it generic using the template T makes this really reusable. Rather than just having a "DVD" type implementation and coping and pasting for another.
public static T CreateObjectFromRow<T>(DataRow row)
{
var newObject = new T();
if (row != null) SetAllProperties(row, newObject);
return newObject;
}
public static void SetAllProperties<T>(DataRow row, T newObject)
{
var properties = typeof(T).GetProperties();
foreach(var propertyInfo in properties)
{
SetPropertyValue(row, newObject, propertyInfo);
}
}
public static void SetPropertyValue(DataRow row, T newObject, PropertyInfo propertyInfo)
{
var columnAttribute = propertyInfo.FindAttribute<SqlMetaAttribute>();
if (columnAttribute == null) return;
// If the row type is different than the object type and exception will be thrown, but that is
// okay because if that happens you have to fix your object you are using, or might need some
// more custom code to help you with that.
propertyInfo.SetValue(newObject, row.GetValue<object>(columnAttribute.ColumnName), null);
}
// Extension method for row.GetValue<object> used above
public static T GetValue<T>(this DataRow row, string columnName)
{
if (row.ColumnNameNotFound(columnName) || row.Table.Columns[columnName] == null || row[columnName] is DBNull)
{
return default(T);
}
return (T)row[columnName];
}
I am trying to create a specific HtmlHelper table extension to reduce the spaghetti code in my View.
Taking a list of domain objects I would like to display a table that is a little bit more intelligent in using the properties of the domain object as columns. In addition, I would like to disable showing of some properties as columns. An idea would be to decorate properties with attributes that tell it not to be shown.
Hopefully that makes sense but here's where I got to so far...
public static string MyTable(this HtmlHelper helper, string name,
IList<MyObject> items, object tableAttributes)
{
if (items == null || items.Count == 0)
return String.Empty;
StringBuilder sb = new StringBuilder();
BuildTableHeader(sb, items[0].GetType());
//TODO: to be implemented...
//foreach (var i in items)
// BuildMyObjectTableRow(sb, i);
TagBuilder builder = new TagBuilder("table");
builder.MergeAttributes(new RouteValueDictionary(tableAttributes));
builder.MergeAttribute("name", name);
builder.InnerHtml = sb.ToString();
return builder.ToString(TagRenderMode.Normal);
}
private static void BuildTableHeader(StringBuilder sb, Type p)
{
sb.AppendLine("<tr>");
//some how here determine if this property should be shown or not
//this could possibly come from an attribute defined on the property
foreach (var property in p.GetProperties())
sb.AppendFormat("<th>{0}</th>", property.Name);
sb.AppendLine("</tr>");
}
//would be nice to do something like this below to determine what
//should be shown in the table
[TableBind(Include="Property1,Property2,Property3")]
public partial class MyObject
{
...properties are defined as Linq2Sql
}
So I was just wondering if anyone had any opinions/suggestions on this idea or any alternatives?
Looks good so far, but Gil Fink may have already done the work for you here: http://blogs.microsoft.co.il/blogs/gilf/archive/2009/01/13/extending-asp-net-mvc-htmlhelper-class.aspx
I strongly suggest to use MvcContrib's Grid. If you decide not to, at least you can take a look at how they solved the table generation interface problem.
After about an hour of work I was able to create what I wanted. My solution was to create an attribtue on the domain object class which specified which properties were visible in my table.
Based on the BindAttribute attribute in MVC 1.0 (having a look at the source code), I created a TableProperty attribute.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class TableProperty : Attribute
{
private string m_include;
private string[] m_includeSplit;
public TableProperty()
{
m_includeSplit = new string[0];
}
public string Include
{
get
{
return (m_include ?? string.Empty);
}
set
{
m_include = value;
m_includeSplit = value.Split(',');
}
}
public bool IsPropertyAllowed(string propertyName)
{
return IsPropertyAllowed(propertyName, m_includeSplit);
}
internal static bool IsPropertyAllowed(string propertyName, string[] includeProperties)
{
return ((includeProperties == null) || (includeProperties.Length == 0)) || includeProperties.Contains<string>(propertyName, StringComparer.OrdinalIgnoreCase);
}
}
This allowed me to decorate my domain object with this attribute...
[TableProperty(Include="Property1,Property2,Property3")]
public partial class MyObject
{ ...
Then inside the BuildTableHeader I used reflection to get the properties of the object and match each property to the allowed list.
private static void BuildTableHeader(StringBuilder sb, Type p)
{
sb.AppendLine("<tr>");
TableProperty tp = p.GetCustomAttributes(typeof(TableProperty), true)[0];
foreach (var property in p.GetProperties())
if (tp.IsPropertyAllowed(property.Name))
sb.AppendFormat("<th>{0}</th>", property.Name);
Please note this solution worked for me in my little application however will be looking more at MvcContrib's Grid for a better implementation.