Using reflection to set the value of an Int32 - c#

I want to use reflection to set some fields according to data from a file. The information that I can have is TypeName, TypeValue and FieldName.
While this is trivial on classes (Activator.CreateInstance and PropertyInfo.SetValue), I am a bit dumbstruck when it comes to value types like Int32 which does not have any properties. I see that IsValueType is true on those Types, but as my TypeValue is a string (i.e. string TypeValue = "400"), I don't know how to assign it.
Do I have to use GetMethods() to check if there is a .Parse Method? Is this something for a TypeConverter?
I know I could just hardcode some common value types (there aren't that many anyway) and have a big switch() statement, but I wonder if there is something that automagically does a "Convert String to T" conversion?

// get the type converters we need
TypeConverter myConverter = TypeDescriptor.GetConverter(typeof(int));
// get the degrees, minutes and seconds value
int Degrees = (int)myConverter.ConvertFromString(strVal);
this should help

ArsenMkrt is right; TypeConverter is the way to go here; some extra thoughts, though:
You might consider using "component model" rather than reflection; i.e. instead of typeof(T).GetProperties(), consider TypeDescriptor.GetProperties(typeof(T)). This gives you a set of PropertyDescriptor records instead of the reflection PropertyInfo. Why is this handy?
because people can actually specify a converter per property (below) - this is exposed as prop.Converter on PropertyDescriptor
if the file is big, you can get a performance boost by using HyperDescriptor
As an example of a property with custom converter:
[TypeConverter(typeof(CurrencyConverter))] // bespoke
public decimal TotalPrice {get;set;}

Related

Accessing Binding from Type Converter?

I've spent a fair bit of time trying a number of different ways to solve an issue I'm having, to no avail, so I'm hoping someone here can help.
I have a Text Box element with Two-Way binding, which utilises a Type Converter to convert the value from a string to a custom Data type, say, MyCustomType. This is working fine, however due to a change in my project's requirements, I now need to perform extra processing prior to the conversion taking place.
In order to perform this extra processing, however, I need to be able to access the "source" text box, or the binding context. Neither of which I have been able to access.
Is there any way to access the source text box, from a Type Converter's ConvertFrom() method?
I have tried to use the ITypeDescriptorContext parameter passed (by WPF) to the ConvertFrom() method, however most of the properties therein are null.
i.e.
public class MyCustomTypeConverter : TypeConverter
{
...
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
// Context is
return new MyCustomType(value);
}
...
}
I have also tried using a MultiValueConverter, and avoiding the Type converter entirely, however this led to a LOT of extra code, and didn't really help. I would prefer to avoid going down this route, as a Type Converter is much more elegant.
Any advice/assistance would be greatly appreciated! :)
EDIT: I ended up changing the way that validation is performed (using INotifyDataError instead of validating on exceptions), and ended up re-writing the ConvertFrom() method in my Type Converter, such that I wouldn't need to access the TypeDescriptor's context anymore.
I wouldn't recommend using the context from the ConvertFrom() method, as it (being a private property) isn't guaranteed that the property will exist in the future (though I haven't read anything to support this, it is best to assume that private properties can be removed/renamed without notification from the MS development team), and it isn't set when setting a property's value programmatically, like so:
TypeConverter converter = TypeDescriptor.GetConverter(typeof(MyCustomType));
converter.ConvertFrom(mySourceValue);
If you're reading this and really need to access the context parameter, you can do so using my method below, at your own risk.
I was able to solve this by interrogating the ValueConverterContext class, and accessing the private _targetElement field, like this:
var sourceTextBox = context.GetType().GetField("_targetElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(context)
Thanks for your help nonetheless. :)
edit: To access the Bindings for this TextBox, you can simply cast sourceTextBox as TextBox and then:
var BindingExpression = sourceTextBox.GetBindingExpression(TextBox.TextProperty);

How can I get a variable/field name through reflection on properties?

Lets say you have:
PropertyInfo propInfo; // Assume it was already initialized with property of a private field
(private int m_Number)
If I'll do propInfo.PropertyType.Name I guess I will get something like int32 or int.
Two questions:
1. How can I extract the variable name "m_Number" through propInfo.
Note: Once I was able to do so by iterating a FieldInfo instead of propInfo.
2. If I want to use reflection to know all kind of fields of a given class, what should be the right way:
A. Iterating over all properties(in assumption every field has a property)
B. Iterating over all the fields directely.
Thanks
A property is not necessarily related to a field - in fact, a property is a little more than a syntactic sugar on top of a pair of functions.
If your code uses some sort of a convention for naming variables that back properties (such as prepending them with m_, as in your example) you could rely upon that convention to retrieve the variable name. In all other cases, there is no direct connection, and no way to retrieve that relationship through the reflection API.

Creating DescriptionAttribute on Enumeration Field using System.Reflection.Emit

I have a list of strings which are candidates for Enumerations values. They are
Don't send diffs
500 lines
1000 lines
5000 lines
Send entire diff
The problem is that spaces, special characters are not a part of identifiers and even cannot start with a number, so I would be sanitizing these values to only chars, numbers and _
To keep the original values I thought of putting these strings in the DescriptionAttribute, such that the final Enum should look like
public enum DiffBehvaiour
{
[Description("Don't send diffs")]
Dont_send_diffs,
[Description("500 lines")]
Diff_500_lines,
[Description("1000 lines")]
Diff_1000_lines,
[Description("5000 lines")]
Diff_5000_lines,
[Description("Send entire diff")]
Send_entire_diff
}
Then later using code I will retrieve the real string associated with the enumeration value, so that the correct string can be sent back the web service to get the correct resource.
I want to know how to create the DescriptionAttribute using System.Reflection.Emit
Basically the question is where and how to store the original string so that when the Enumeration value is chosen, the corresponding value can be retrieved.
I am also interested in knowing how to access DescriptionAttribute when needed.
Ok, if you really want to use reflection:
DiffBehvaiour value = DiffBehvaiour.Dont_send_diffs;
FieldInfo enumField = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = (DescriptionAttribute)enumField.
GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
Console.WriteLine(attribute.Description);
$> Don't send diffs
Obviously there is no error handling, etc, but the basic idea is there.
Update
I now think I see the point of your question, which myself and the other people that answered actually missed.
You want to decorate an enum with attributes at runtime i.e. add attributes to a type at runtime. Adding attributes to a type at runtime is not possible.
However these is support in the .Net for a type metadata engine via : TypeDescritor:
MSDN http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx
Example http://geekswithblogs.net/abhijeetp/archive/2009/01/10/dynamic-attributes-in-c.aspx
The TypeDescritor framework allows you to dynamically provide type information rather than actually dynamically decorating types directly - it is a layer of indirection.
You may be able to bend this mechanism to support what you want to do, but at the end of the day you will need to maintain a lookup for your enum members to provide the description strings. Using a lookup structure to maintain a mapping between your enum members and description string was my first answer and the first answer to this question...
You could write a generic method like this:
class EnumExtensions
{
public static string GetDescription<TEnum>(TEnum value)
// inexpressible generic constraint TEnum : System.Enum
{
// reflection lookup of this value per #chibacity answer
}
public static IDictionary<TEnum,string> GetDescriptions<TEnum>()
// inexpressible generic constraint TEnum : System.Enum
{
// do the reflection lookups once and build a dictionary
var result = new Dictionary<TEnum, string>();
foreach(string name in Enum.GetNames(typeof(TEnum))
{
var value = (TEnum)Enum.Parse(typeof(TEnum), name);
var description = GetDescription(value);
result.Add(value, description);
}
return result;
}
}

Should I use values or keys?

I am warpping an ArcGIS IFeature object with a class that has my required properties to get and set them easily.
Basically, the get and set operations just use feature.get_value(index) and feature.set_value(indes, value), and expose the strongly typed value.
I have several fields that use a domain (basically, an IDictionary<string, object>) to represent common properties across the application.
At first I figured I would only use the keys of the domain (which are normal int values) in my wrapping class, and use the domain in my ToString() method, to translate to strings for the UI.
Later I figured out I can use strings in my applicaiton (which makes it easier to pass around nulls, as the actual domain fields are nullable most of the time), and only change those fields' getters and setters to use GetDomainValue(index) and SetDomainValue(index, value) method that will translate between the key and value to/from the underlying feature object.
What approach do you think is better? I figured the string approach is a bit more "persistent ignorant", as my class doesn't care how the values are being saved, just their string representation.
On the other hand, it makes the code jump through loops a bit - instead of returning what's in the feature, every getter needs to iterate the domain.
You might want to think about representing your domain fields with Nullable< Int32>. This would give you a way to represent features that have a domain value specified but it also allows you to directly specify null where appropriate.
I ended up sticking with the domain values, so that I can also verify that the calling code passed a valid value.

Property Name and need its value

I have a name of a property and need to find its value within a Class, what is the fastest way of getting to this value?
I am making the assumption that you have the name of the property in runtime; not while coding...
Let's assume your class is called TheClass and it has a property called TheProperty:
object GetThePropertyValue(object instance)
{
Type type = instance.GetType();
PropertyInfo propertyInfo = type.GetProperty("TheProperty");
return propertyInfo.GetValue(instance, null);
}
I assume you mean you have the name of the property as a string. In this case, you need to use a bit of reflection to fetch the property value. In the example below the object containing the property is called obj.
var prop = obj.GetType().GetProperty("PropertyName");
var propValue = prop.GetValue(obj, null);
Hope that helps.
If you're interested in speed at runtime rather than development, have a look at Jon Skeet's Making reflection fly and exploring delegates blog post.
Just use the name of the property. If it is a nullable property (e.g. int ? property) use property.Value.
At runtime you can use reflection to get the value of the property.
Two caveats:
Obfuscation: An obfuscator may change
the name of the property, which
will break this functionality.
Refactoring: Using reflection in this
manner makes the code more difficult
to refactor. If you change the name
of the property, you may have to
search for instances where you use
reflection to get the property value
based upon name.

Categories