Reflection from DTO - c#

I have 1 dto, statEMailDTO, which has a field that holds the Field Names of what I'm looking for (they are comma delimited.
var emailParams = statEmailDTO.EmailParam.ToString().Split(',');
for (int i = 0; i < emailParams.Length; i++) {
var fieldName = emailParams[i].ToString();
etc.
But, then how do I use Reflection to then get the Actual value of ``fieldName which is found in a different DTO, siDTO.
So let's say that fieldName = "SuggestionItemID", I then what to get the value of siDTO.SuggestionItemID.
I haven't done a lot of reflection in the past. Sure, I read up on PropertyInfo, but it's just not clicking.
Thoughts?

Like this:
PropertyInfo property = typeof(SomeType).GetProperty(fieldName);
object value = property.GetValue(instance, null);

Related

Referencing a field with a variable

I was wondering if it was possible to referance a class field via variable. like so:
int variable = 0;
while (variable > 3)
{
class._fieldvariable = something;
i++
}
where if I have fields: _field1, _field2, _field3 I can iterate through them all.
The main reason for doing this is I have an sql query that will append multiple records and I'd rather not have to do all the parameters multiple times but rather something like this:
while (i < 4)
}
command.Parameters.AddWithValue("#Alpha1", _alphai01.ToString());
i++
}
to let me set parameters 3 times with _alpha101, _alpha201 and _alpha301 are used for three different queries.
thanks!
Associate properties to the fields, all of them with get/set access.
If we're really talking about three fields, a more or less clean way to do so is by using a function GetField(int index) which would return the corresponding property. Then your code can be
class.GetField(i) = something;
An array is better in the more general case (for example, if the number of fields is expected to change).
I would prefer not to use reflection for such a simple purpose.
You can use invokeMember to call a certain setter of a property:
Object obj; //your instance;
obj.GetType().InvokeMember("Alpha1",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "ValueForAlpha1");
that's equal to
obj.Alpha1 = "ValueForAlpha1";
http://msdn.microsoft.com/en-US/library/vstudio/66btctbe.aspx
You could use reflection like this
if you have a class A
public class A
{
int field1, field2, field3;
}
you could set these fields like this
A obj = new A();
for (int i = 1; i < 4; i++)
{
FieldInfo field = obj.GetType().GetField(String.Format("field{0}", i), BindingFlags.NonPublic | BindingFlags.Instance);
if (null != field)
{
field.SetValue(obj, i);
}
}

Looping though a dictionary containing objects

I have the following loop over a dictionary type collection
foreach(KeyValuePair<Vector2, Object> entry in v_map.map_set)
{
}
I want to access the object properties, but the expected syntax doesn't work. E.G:
foreach(KeyValuePair<Vector2, Object> entry in v_map.map_set)
{
Object ob = entry.Value;
ob.property;
}
Fails because C# can't find the property wanted.
So, how do I access the desired properties?
solution:
foreach(KeyValuePair<Vector2, Object> entry in v_map.map_set)
{
if (entry.Value is warehouse)
{
warehouse ob = (warehouse)entry.Value;
}
}
If you know the type of the objects that are in the KeyValuePair, you can cast it to that type, and you will be able to find the properties you need.
And if you have several different objects stored, you can check which type it is by using is.
Like so:
if(entry.Value is Foo)
{
Foo lFoo = (Foo)entry.Value;
}
else if(entry.Value is Bar)
{
Bar lBar = (Bar)entry.Value;
}
You can make use of Refection to get the value of proerty of the object.
something like this
PropertyInfo info2 = object.GetType().GetProperty("prpertyname");
Object val = info2.GetValue(object, null);
You need to cast entry.Value to the type you need. The Object type itself isn't going to expose the properties you want.
If you just need to access the values, and you know the expected type you can use
foreach(ExpectedType value in v_map.map_set.Values.OfType<ExpectedType>())
{
var property = value.Property;
}
where Property is a property on ExpectedType.
The problem is that you're using an object which isn't typed. So you're going to need to use reflection like this:
PropertyInfo pi = ob.GetType().GetProperty("PropertyName");
var val = pi.GetValue(ob, null);
Now, if the property isn't public then you'll need to employ something else like this:
PropertyInfo pi = ob.GetType().GetProperty("PropertyName", BindingFlags.Instance | BindingFlags.NonPublic);
var val = pi.GetValue(ob, null);
Now, if this is actually a field you're trying to get to, you're going to need to do something different even yet:
FieldInfo fi = ob.GetType().GetField("fieldName");
var val = fi.GetValue(ob);
GetProperty method
BindingFlags enumeration
GetField method

How to convert one type to another using reflection?

I have a two types that are very similar (i.e. the member names are very similar).
Is there an elegant way to copy one type to another, without having to copy each individual member by hand?
Update
Here is some sample source code:
main()
{
FromCsvFile x = new FromCsvFile(fileName);
OptionsEnt y = x.ToOptionsEnt(); // See helper function below.
}
// Chained helper function to convert type "FromCsvFile" to type "OptionsEnt".
// Want to replace this with something more elegant (perhaps with reflection?).
// Notice the corner cases, i.e. the "ExpirationDate" is a special conversion.
public static OptionsEnt ToOptionsEnt(this FromCsvFile fromCsvFile)
{
return new OptionsEnt
{
Last = fromCsvFile.Last,
Ask = fromCsvFile.Ask,
Bid = fromCsvFile.Bid,
Delta = fromCsvFile.Delta,
EODsnapshotNewYorkTime = fromCsvFile.EODsnapshotNewYorkTime,
Exchange = fromCsvFile.Exchange,
ExpirationDate = fromCsvFile.Expiration.ToTypeIceDate(),
Gamma = fromCsvFile.Gamma,
IV = fromCsvFile.IV,
LastDate = fromCsvFile.Date.ToTypeIceDate(),
AdjustedStockClose = fromCsvFile.AdjustedStockClose,
MeanPrice = fromCsvFile.MeanPrice,
OptionType = fromCsvFile.OptionType == "C" ? OptionTypeEnum.enCall : OptionTypeEnum.enPut,
OpenInterest = fromCsvFile.OpenInterest,
Rho = fromCsvFile.Rho,
StockSymbol = fromCsvFile.SymbolStock,
StrikePrice = fromCsvFile.StrikePrice,
Symbol = fromCsvFile.Symbol,
StockPriceForIV = fromCsvFile.StockPriceForIV,
Star = fromCsvFile.Star,
Theta = fromCsvFile.Theta,
Vega = fromCsvFile.Vega,
Volume = fromCsvFile.Volume,
IVnotInterpolated = fromCsvFile.IVnotInterpolated
};
}
Update
Decided to go with AutoMapper.
Here is the code that replaces all of the code above (assuming that all member names are of the same name and type):
main()
{
FromCsvFile x = new FromCsvFile(fileName);
OptionsEnt y = Mapper.Map<FromCsvFile, OptionsEnt>(x);
}
As we need some custom converters (i.e. DateTime >> IceDateTime), here is the extra line of code that includes a custom mapping for the parameter "ExpirationDate". Adding this line avoids an exception being thrown as it doesn't know how to convert dates from one format to another.
Mapper.CreateMap<DateTime, typeIceDate>().ConvertUsing(ConverterIceTypeIceDate.ToTypeIceDate);
Maybe Automapper?
For example:
Mapper.CreateMap<FromCsvFile, OptionsEnt >();
return Mapper.Map<FromCsvFile, OptionsEnt>(fromCsvFile);
Use something like AutoMapper for that. It will allow you to simply define that class OptionsEnt should be mapped to FromCsvFile and if they have the properties with same names and types then you won't need to define anything else.
Otherwise you'll have to iterate by properties.
See Copyable: A framework for copying or cloning .NET objects. Its slightly slower (it uses reflection), but it has one advantage: you can alter the source to handle corner cases where the member variables need a little bit of work to convert.
For example, in the sample source code in the question, member variable "ExpirationDate" is of type "DateTime" in one type, and type "IceDateTime" in the other (you need to convert the date format with the extension method .ToDateTime).
Here is the source (see the original blog entry for more source):
// Modification to original source code.
Type type = instance.GetType();
if (instance.GetType().Name == "DataTable")
{
// Added to handle custom type.
DataTable dt = (DataTable)instance;
copy = dt.Copy();
}
else if (instance.GetType().Name == "DataSet")
{
// Added to handle custom type.
DataSet ds = (DataSet)instance;
copy = ds.Copy();
}
else
{
// This is the original source.
while (type != null)
{
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
object value = field.GetValue(instance);
if (visited.ContainsKey(value))
field.SetValue(copy, visited[value]);
else
field.SetValue(copy, value.Clone(visited));
}
type = type.BaseType;
}
}
return copy;

Setting alignment property by reflection with a string value

I'd like to set align property (horizontal/vertical) of an object through reflection, with a value of type string. I use something like
private void SetPropertiesFromString(object nav, string properties)
{
Regex r = new Regex("`(?<property>[^~]*)~(?<values>[^`]*)");
MatchCollection mc = r.Matches(properties);
Type type = nav.GetType();
for (int i = 0; i < mc.Count; i++)
{
PropertyInfo prop = type.GetProperty(mc[i].Groups["property"].Value);
prop.SetValue(nav, Convert.ChangeType(mc[i].Groups["values"].Value, prop.PropertyType), null);
}
}
(Quite same like this)
My problem is, that I'm reading properties from XML, there is only HorizontalAlignment="Stretch". Than I create new entity of Control and I don't know, how to set property like HorizontalAlignment, where value is "Stretch" etc. It causes exception "Invalid cast from 'System.String' to 'System.Windows.HorizontalAlignment'."
HorizontalAlignment is an enum type. System.Enum.Parse lets you convert a string to the corresponding enum value.

Mapping special null constant values into DBNull in a DataTable

I'm working with an existing object framework that uses special values to represent NULL for primitives int, DateTime, long. Data containing these values are added to a DataTable and displayed in third-party controls such as XtraGrid.
All is fine, except when aggregates are applied to the data. In this case, obviously the special values are processed instead of the NULL entries.
So I think the best solution is to map the values to/from DBNull when putting into the DataRow. I thought about subclassing the DataTable and DataRow, but the base classes don't allow overriding of the accessors.
I could add extra Get/Set functions to the subclasses but this relies on remembering to use them. I could add static helper functions instead of subclassing, but this has the same problem.
Is there a more elegant solution?
Update
It's the grid itself that is doing the aggregation, as it has flexible controls to let the user define summaries at run-time. So I think the only real solution is to map to/from DBNull somehow, just looking for an elegant way of doing this.
You may create an extension method to help you fill the datatable and convert values to dbnull:
public static class DataExtensions
{
public static DataRow AddRow(this DataRowCollection rowCollection, params object[] values)
{
object[] newValues = new object[values.Length];
for(int i=0;i<values.Length;i++)
{
object value = values[i];
if (value != null)
{
Type t = value.GetType();
//check for min value only for value types...
if (t.IsValueType)
{
//maybe you can do some caching for that...
FieldInfo info = t.GetField("MinValue",
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
);
if (info != null)
{
object o = info.GetValue(null);
if (value.Equals(o)) //very important == will return false
{
value = DBNull.Value;
}
}
}
}
newValues[i] = value;
}
return rowCollection.Add(newValues);
}
}
And then you will be able to write something like:
t.Rows.AddRow(a,b,c,d,e);
maybe you can create conditional aggregates with IIF like (silly example):
DataTable t= new DataTable();
t.Columns.Add("id");
t.Columns.Add("id2");
t.Columns.Add("id3", typeof(int), "IIF(id="+int.MinValue.ToString()+",id2,id+id2)");
for (int i = 0; i < 5; i++)
{
t.Rows.Add(new object[] { i, 2 * i });
}
t.Rows.Add(new object[] { int.MinValue, 2000});
Edit: adapted to your comment on other post.

Categories