I want to use something similar as:
object ob;
var props = ob.GetType().GetProperties();
List<Element> list = new List<Element>();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(String))
list.Add(makeStringProperty(prop));
else if (prop.PropertyType == typeof(int))
list.Add(makeIntProperty(prop));
else
{
}
}
which adds something to the given list for every property in a given object. Now I want to add a clause for also adding enum-variables, including getting all its values by Enum.GetValues() f.e..
That would be easy for any one given enum, but I want this to be generic for every possible enum,
so for example if ob would have:
enum Weather {
sunny,
rainy,
cloudy
}
Weather weather = sunny;
enum Places {
beach,
mall,
home
}
Places place = beach;
I would be able to get both variables themselves AND all the values of both Enums.
Of course I can't directly check typeof(Enum) or anything.
Does someone have a clue?
else if(prop.PropertyType.IsEnum)
{
var values = Enum.GetValues(prop.PropertyType);
}
It's something like
typeof(Weather).GetFields()
or
ob.GetType().GetFields()
if you want to use reflection directly on an enum type. The members of an enum are a kind of static fields.
But you can also use
Enum.GetValues(ob.GetType())
In any case, if there's doubt, you should check if it is an enum or not first:
var typeOfOb = ob.GetType();
if (typeOfOb.IsEnum)
{
// use Enum.GetValues(typeOfOb) here
}
Note: System.Type is the class used for both a type determined compile-time, like typeof(Weather), and a type determined run-time, like ob.GetType(). So you can use both as an argument to the GetValues(System.Type) static method.
Related
Well, I need to repeat same code for many properties.
I've seen examples taking Action delegates, but they don't fit quite well here.
I want something like this: (see explanation below)
Dictionary<Property, object> PropertyCorrectValues;
public bool CheckValue(Property P) { return P.Value == PropertyCorrectValues[P]; }
public void DoCorrection(Property P) { P.Value = PropertyCorrectValues[P]; }
.
I want to have a dictionary containing many properties and their respective "correct" values. (I know it's not well declared, but that's the idea). Properties are not necessarely inside my class, some of them are in objects of different assemblies.
A method bool CheckValue(Property). This method must access the actual value of the property and compare to the correct value.
And a method a void DoCorrection(Property). This one sets the property value to the correct value.
Remember I have many of those properties, I wouldn't like to call the methods by hand for each property. I'd rather iterate through the dicionary in a foreach statement.
So, the main question is in the title.
I've tried the by ref, but properties don't accept that.
Am I obligated to use reflection??? Or is there another option (if I need, reflection answer will be accepted as well).
Is there anyway I can make a dictionary with pointers in C#? Or some kind of assignment that changes the value of variable's target instead of changing the target to another value?
Thanks for the help.
You can do this using reflection. Get a list of the properties on the object of interest with typeof(Foo).GetProperties(). Your PropertyCorrectValues property can have type IDictionary<PropertyInfo, object>. Then use the GetValue and SetValue methods on PropertyInfo to perform the desired operations:
public bool CheckProperty(object myObjectToBeChecked, PropertyInfo p)
{
return p.GetValue(myObjectToBeChecked, null).Equals(PropertyCorrectValues[p]);
}
public void DoCorrection(object myObjectToBeCorrected, PropertyInfo p)
{
p.SetValue(myObjectToBeCorrected, PropertyCorrectValues[p]);
}
In addition to Ben's code I'd like to contribute the following code fragment:
Dictionary<string,object> PropertyCorrectValues = new Dictionary<string,object>();
PropertyCorrectValues["UserName"] = "Pete"; // propertyName
PropertyCorrectValues["SomeClass.AccountData"] = "XYZ"; // className.propertyName
public void CheckAndCorrectProperties(object obj) {
if (obj == null) { return; }
// find all properties for given object that need to be checked
var checkableProps = from props
in obj.GetType().GetProperties()
from corr in PropertyCorrectValues
where (corr.Key.Contains(".") == false && props.Name == corr.Key) // propertyName
|| (corr.Key.Contains(".") == true && corr.Key.StartsWith(props.DeclaringType.Name + ".") && corr.Key.EndsWith("." + props.Name)) // className.propertyName
select new { Property = props, Key = corr.Key };
foreach (var pInfo in checkableProps) {
object propValue = pInfo.Property.GetValue(obj, null);
object expectedValue = PropertyCorrectValues[pInfo.Key];
// checking for equal value
if (((propValue == null) && (expectedValue != null)) || (propValue.Equals(expectedValue) == false)) {
// setting value
pInfo.Property.SetValue(obj, expectedValue, null);
}
}
}
When using this "automatic" value correction you might also consider:
You cannot create a PropertyInfo object just by knowing the property name and independently of the declaring class; that's why I chose string for the key.
When using the same property name in different classes then you might need to change the code that is doing the actual assignment because the type between the correct value and the property type might differ.
Using the same property name in different classes will always perform the same check (see point above), so you might need a syntax for property names to restrict it to a specific class (simple dot notation, doesn't work for namespaces or inner classes, but might be extended to do so)
If needed you can replace the "check" and "assign" part with separate method calls, but it might be done inside the code block as stated in my example code.
Why this simple code doesnt work?
var abc = new[]{1,2,3,4}.Select(x => default(typeof(x)));
i expect something like array of zeros but get compiler error. So how i can default values in lambda expressions?
In my real application i have meta class with type Type
public class FieldInfo
{
public Type type
}
I get IEnumerable<FieldInfo> as parameter to my method and want return an array of default values for each type (object[])
This is the problem:
typeof(x)
You're using the typeof operator as if it's a method call, taking a value. It's not. It needs a compile-time type name or type parameter (or unbound type such as Dictionary<,>, or void).
The same is try with the default operator.
So that's what's wrong - but without knowing what you're trying to achieve, we can't actually advise you on how to fix it. You might just want something like this:
public static IEnumerable<T> SelectDefault<T>(this IEnumerable<T> source)
{
return source.Select(x => default(T));
}
Then this:
var abc = new[]{1,2,3,4}.SelectDefault().ToArray();
... would give you an int[] with all values zero.
EDIT: Now we have more information, it's easier to provide what you want, which is basically a method to get the default value from a Type, boxing as appropriate:
public static object GetDefaultValue(Type type)
{
// Non-nullable value types should be boxed, basically
if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
{
// Not the swiftest approach in the world, but it works...
return Activator.CreateInstance(type);
}
// Everything else defaults to null
return null;
}
So you'd have something like:
var defaults = fields.Select(field => GetDefaultValue(field.type));
(Where field is a FieldInfo as per the question - I'm deliberately not calling GetType() here.)
Do you mean this?
var abc = new[]
{
1, 2, 3, 4
}
.Select(x = > {
var xType = x.GetType();
if (xType.IsValueType)
{
return Activator.CreateInstance(xType);
}
else
{
return null;
}
})
You can't get the default value at runtime this way, default() and typeof() are compile time features. But you can try this suggestion. It uses Activator.CreateInstance to get the default value for a value type at runtime.
The compiler needs a compile-time type:
var abc = new[]{1,2,3,4}.Select(x => default(Int32));
will generate all 0's. I have no idea what you are trying to achieve with this, though, because all this does is return an empty array with the default value.
I have a sql stored procedure that I run that returns a class name. For example it returns "orange". I have a class called "orange". Is it possible to use that return string to access orange.GrabFiles?
Thanks!
You can use System.Reflection to get the class which you need and invoke the method you want to call.
To do this you can iterate though all types of the assembly and pick the right one for you. If you have special names you can use attributes to link a specific type with a special name.
Search the type
// Type to find
String name = "orange";
// I assume you only use one assembly
Assembly asm = Assembly.GetCallingAssembly();
// Iterate though all types
foreach (Type item in asm.GetTypes())
{
if (item.Name == name)
{
return item;
}
else
{
// A class can have multiple SpecialNameAttributes, this is a attribute you have to create
SpecialNameAttribute[] attributes = (SpecialNameAttribute[])item.GetCustomAttributes(typeof(SpecialNameAttribute));
foreach (SpecialNameAttribute attribute in attributes)
{
if (attribute.Name == name) return item;
}
}
}
return null;
Invoke the method
With instance creation:
Object instance = Activator.CreateInstance(typeFound);
typeFound.GetMethod("GrabFiles").Invoke(instance, ...);
Without instance:
typeFound.GetMethod("GrabFiles").Invoke(null, ...);
Assuming the namespace for "orange" is "fruits" you can do the following:
dynamic d = Activator.CreateInstance(Type.GetType("fruits.orange"));
d.GrabFiles();
Quite simple and straight-forward as long as you know what your code is doing.
If there are only a few return values, all known at compile time, then it will be simpler to check the result and branch accordingly (using switch or a sequence of ifs).
If you need more dynamic behaviour you can do Type typeToCall = Type.GetType(typeName); and then use typeToCall.InvokeMember(...).
I am writing a ConfigParser class, which reads from a config file structured like this:
[Section]
option1 = foo
option2 = 12
option3 = ;
...
The information read is actually stored in a Dictionary<string, string>. What i'd like to achieve is the following:
struct ConfigStruct
{
public string option1;
public int option2;
public char option3 { get; set; }
// Any other _public_ fields or properties
}
ConfigParser Cp = new ConfigParser("path/to/config/file"); // Loads content
ConfigStruct Cs = Cp.CreateInstance<ConfigStruct>("Section");
Console.WriteLine(Cs.option1); // foo
Console.WriteLine(Cs.option2.ToString()); // 12
Console.WriteLine(Cs.option3.ToString()); // ;
The struct (or class, it doesn't matter) ConfigStruct, is application-specific, and the ConfigParser class should know nothing about it. Basically, I want to parse the value from a specific option, and store it into the field/property with the same name. Parsing should be done according to the field/property type.
I've developed a stub method for it:
public T CreateInstance<T>(string Section) where T : new()
{
// Gets options dictionary from loaded data
Dictionary<string, string> Options = this.Data[Section];
T Result = new T();
Type StructType = Result.GetType();
foreach (var Field in StructType.GetFields())
{
if (!Options.ContainsKey(Field.Name))
continue;
Object Value;
if (Field.FieldType == typeof(bool))
Value = Boolean.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(int))
Value = Int32.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(double))
Value = Double.Parse(Options[Field.Name]);
else if (Field.FieldType == typeof(string))
Value = Options[Field.Name];
else if (Field.FieldType == typeof(char))
Value = Options[Field.Name][0];
// Add any ifs if needed
else { /* Handle unsupported types */ }
Field.SetValue(Result, Value);
}
foreach (var Property in StructType.GetProperties())
{
// Do the same thing with public properties
}
return Result;
}
Do you think this is the right approach to the problem? Or should I move the responsability of initializing the struct to the application logic instead of the ConfigParser class? I know it's more efficient, but using reflection I write this method only once, and works for every struct.
Should I use reflection to invoke Parse() so that I can avoid all those ifs? Or you'd rather make those conversions type by type, to prevent unexpected behaviour?
Thanks for your time.
Assuming there is a specific reason why you are not using app.config/web.config or other built-in configuration files.
I think this comes down to what the rest of the application is doing, but personally I would do it this way. It allows you to get the return type cleanly and you are not passing an extra stuct down the stack that you don't need to be.
Reflection is a fantastic tool but has some overhead so if the list of types is finite then specifying them manually is more efficient, or alternately only reflecting the unknown types. Also I would change your if blocks to a switch statement, you will gain efficiencies if the IL complier can fully optimise the condition block.
I think there is a simpler solution. You could use a custom section handler to store your settings, custom section handlers are well described here: http://devlicio.us/blogs/derik_whittaker/archive/2006/11/13/app-config-and-custom-configuration-sections.aspx).
I'm trying to write a custom method to populate a ListView control using Generics:
private void BindDataToListView(List<T> containerItems)
{
this.View = View.Details;
this.GridLines = true;
this.FullRowSelect = true;
if (this.Items.Count > 0)
this.Items.Clear();
this.BeginUpdate();
int i = 0;
foreach (T item in containerItems)
{
// do something
}
this.EndUpdate();
}
The parameter containerItems can have many items since I'm using generics. But I get stuck in the foreach loop. How do I access the values in containerItems?
Do I have to use reflection on each instance of T in the foreach loop? I think I do to retrieve the property name. But once I have the property name of the type T, how do I retrieve the value?
The most common way of doing this (with winforms) is via TypeDescriptor; this allow you to use things DataTable the same as classes; the "full" pattern is quite complex (and involves checking for IListSource, ITypedList, etc; however, the short version is; to get the available properties:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
To get a named property:
PropertDescriptor prop = props[propName];
To get a value for an instance (sourceObject):
object val = prop.GetValue(sourceObject);
To render a value as a string (using the designated converter):
string s = prop.Converter.ConvertToString(val);
You could limit T to an interface, and use that interface in the iteration.
What does T represent ?
Like it is now, it is a generic type and it can be ... anything.
So, what I would do, is create an interface IListViewBindable or something like that. That interface could then have a method 'CreateListViewItem' for instance.
Then, I would change the method, so that a constraint is applied to your type-parameter T, saying that T should implement IListViewBindable, like this:
public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}
In your BindDataToListView method, you could then do this:
foreach( T item in containerItems )
{
this.Items.Add (item.CreateListViewItem());
}
If the items in the list are of totally unconstrained type, then you can treat them as simply of type object. You call GetType() to get the type of the object. On that you can call GetProperties() to get an array of PropertyInfo objects. And on those you can call GetValue() to retrieve the value of the property.
If you already know the name of a property, just call GetProperty() to retrieve it:
string valueAsString = item.GetType().GetProperty("Something")
.GetValue(item, null).ToString();
I don't completely understand what you're asking, but I think that this will point you in the right direction. Please ask for clarification if it looks like it can help and it's unclear.
You can access a given property of an object using reflection via
object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");
and you can get the value via
object value = info.GetValue(o, null);
Now, if you're going to be accessing a property of the same name on objects of various types, you should consider adding an interface
public interface IHasThePropertyIWant {
object NameOfPropertyIWant { get; }
}
Then you can enforce this via
void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant
and use it in the look like so
foreach (T item in containerItems) {
object o = item.NameOfPropertyIWant;
// do something with o
}
ObjectListView uses reflection to do exactly what you are trying to do: populate a ListView using reflection. You could save yourself a lot of trouble by using it. It has already solved all the tricky problems you are going to encounter on this path.
If you really, really want to do it yourself, Marc's answer is (of course) completely correct.