I have a static class which only contains string properties. I want to convert that class into a name-value pair dictionary with key=PropName, value=PropValue.
Below is the code I have written:
void Main()
{
Dictionary<string, string> items = new Dictionary<string, string>();
var type = typeof(Colors);
var properties = type.GetProperties(BindingFlags.Static);
/*Log properties found*/
/*Iam getting zero*/
Console.WriteLine("properties found: " +properties.Count());
foreach (var item in properties)
{
string name = item.Name;
string colorCode = item.GetValue(null, null).ToString();
items.Add(name, colorCode);
}
/*Log items created*/
Console.WriteLine("Items in dictionary: "+items.Count());
}
public static class Colors
{
public static string Gray1 = "#eeeeee";
public static string Blue = "#0000ff";
}
Output
properties found: 0
Items in dictionary: 0
It's not reading any properties - can anybody tell me what's wrong with my code?
The members in your Colors class are no properties but fields.
Use GetFields in the place of the GetProperties method.
You might end up with something like (also not the change in the call to GetValue):
var properties = type.GetFields(BindingFlags.Static);
/*Log properties found*/
/*Iam getting zero*/
Console.WriteLine("properties found: " +properties.Count());
foreach (var item in properties)
{
string name = item.Name;
string colorCode = item.GetValue(null).ToString();
items.Add(name, colorCode);
}
You can use linq to condense the conversion to a couple of lines:
var type = typeof(Colors);
var fields = type.GetFields().ToDictionary(f => f.Name, f => f.GetValue(f).ToString());
Use this:
var properties = type.GetFields(BindingFlags.Static|BindingFlags.Public);
Related
Good day,
I need to make function that will iterate on Dictionary that stores variable name and variable`s new value. After that, I need to update class variable with that value.
void UpdateValues(Type type, Dictionary<string, string> values)
{
foreach (var value in values)
{
var fieldInfo = selected.GetComponent(type).GetType().GetField(value.Key);
if (fieldInfo == null) continue;
fieldInfo.SetValue(selected.GetComponent(type), value.Value);
}
}
It works but I want little improvement and I absolutely don't know if it is possible.
As you can see, that function can accept any class, not just one specific.
If I have class like this
class test
{
public string age;
}
And I would use function this way, it would work.
UpdateValues(typeof(test), new Dictionary<string, string>{{"age", "17"}});
Problem is if I have class like this and I would like to update "subfield" (field in field)
class test
{
public string age;
}
class test2
{
public test data;
}
I was thinking that syntax could be something like this, but I have no idea how could I do it.
UpdateValues(typeof(test2), new Dictionary<string, string>{{"data.age", "17"}});
To sum it up, I need to make function that will take class that is stored in another class. Function will iterate trough the dictionary and update fields of class and even her subfields.
I would propose to add a recursive call to your method, to set the properties. I have changed your method a little bit, because i don't have selected object, it takes an object as a parameter
void UpdateValues<T>(T obj, Dictionary<string, string> values)
{
foreach (var value in values)
{
SetProperty(obj, value.Key, value.Value);
}
}
public void SetProperty<T>( T obj, string valueKey, string value, Type type= null)
{
var typeToUse = type ?? typeof(T);
var pointIndex = valueKey.IndexOf(".");
if (pointIndex!=-1)
{
var subKey = valueKey.Substring(0, pointIndex);
var fieldInfo = typeToUse.GetField(subKey);
var propObj = fieldInfo.GetValue(obj)
?? Activator.CreateInstance(fieldInfo.FieldType);
SetProperty(propObj, valueKey.Substring(pointIndex+1), value, fieldInfo.FieldType);
fieldInfo.SetValue(obj, propObj);
}
else
{
var fieldInfo = typeToUse.GetField(valueKey);
if (fieldInfo != null)
fieldInfo.SetValue(obj, value);
}
}
It works even if you define
class test3
{
public test2 data;
}
and call
UpdateValues(t, new Dictionary<string, string>{{"age", "17"}});
UpdateValues(t2, new Dictionary<string, string> { { "data.age", "17" } });
UpdateValues(t3, new Dictionary<string, string> { { "data.data.age", "17" } });
The third parameter of SetProperty method is not really nice, i would avoid it, but i don't know how to solve it with generics, after creating with Activator you get object as a Type, and object doesn't have field age
You are using Dictionary<string, string> as a parameter that allows you to set only string fields, so you must assume that you don't have any other. Actually this will work even if you will use Dictionary<string, object>, that i would suggest to do.
First of all you will need to change your Dictionary variable to use
Dictionary<string, object> if you want to pass a class as a parameter in here.
Secondly Here is an example of how to make it work.
class test
{
public string age;
}
class test2
{
public test data;
}
Lets suppose i have created an instance of test class and added it in a dictionary, to get the fields with reflection and then update the instance of test2 accordingly.
public void UpdateValues(object test2, Dictionary<string, object> dict)
{
var fieldValues = test2.GetType()
.GetFields()
.ToList();
foreach (var value in dict)
{
foreach (var field in fieldValues)
{
if (value.Key == field.Name)
{
bool obj = field.FieldType == typeof(test);
if (obj)
{
if (dict.ContainsKey("data"))
{
var prop = test2.GetType().GetField("data", System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance);
prop.SetValue(test2, dict["data"]);
break;
}
}
else
{
var prop = test2.GetType().GetField(value.Key, System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance);
prop.SetValue(test2, value.Value);
break;
}
}
}
}
}
In the end call you function i have created a Dictionary<string,object> instance to send it as a parameter to the function
object test2 = new test2();
test t = new test();
t.age = "10";
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("data", t);
UpdateValues(test2, dict);
Not sure if this is possible, but is there a way to accomplish this?
given this class:
class A
{
public String B {get;set;}
public String C {get;set;}
public String D {get;set;}
}
Instantiate A and assign V1,V2,V3 to B,C,D respectively
I would want a Dictionary\Matrix\some other structure containing
B:V1
C:V2
D:V3
Preferably without using 3rd party libraries
var a = new A{B = "V1", C = "V2", D = "V3"};
var dictionary = a.GetType()
.GetProperties()
.ToDictionary(prop => prop.Name,
prop => prop.GetValue(a));
var props = typeof(A).GetProperties();
Dictionary<string, string> output=new Dictionary<string,string>();
foreach(PropertyInfo pi in props)
{
var name = pi.Name,
string value= pi.GetValue(this, null) as string;
output[name]=value;
}
simple example for fields and its values (for public fields):
var a = new A("a", "b", "c");
var fields = typeof(A).GetFields();
var dict = new Dictionary<string, string>(fields.Length);
foreach (var fieldInfo in fields)
{
dict.Add(fieldInfo.Name, (string)fieldInfo.GetValue(a));
}
Note this is only a sample and you should add more defensive code to check that the types of the fields are correct etc...
a simple way using reflection:
var a = new A();
.
. fill in a.B... etc
.
.
Dictionary<String, String> dict =
a.GetType()
.GetFields()
.ToDictionary(k => k.Name, v => v.GetValue(a).ToString())
GetFields() returns a FieldInfo[] array so you can check for other things first like fields being defined etc.
When creating a new item; is there any way to access all the field values that are set.
Since I'm using Entity.GetModifiedMembers() method to access the values of the fields that are changed when updating for logging purposes, the purpose is to have the equivalent result through an entity when creating, like a method Entity.GetSetMembers().
So in general, all I need is a key-value pair with "member name" and "value" items.
Example:
public class SomethingEntity
{
public int Id {get;set;}
public string Name {get;set;}
public DateTime Created {get;set;}
public DateTime Modified {get;set;}
}
public Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object entity)
{
//This is what I need, that can take all the objects from an entity and give
//the property-value pairs for the object instance
return RequieredMethod(entity);
}
public ExampleMethod()
{
var newObject = new SomethingEntity() { Name = "SomeName", Created = DateTime.Now };
Entity.insetOnSubmit(newObject);
Entity.SubmitChanges();
var resultList = GetFieldsAndValuesOfCreatedItem(newObject);
foreach (var propertyKeyValue in resultList)
{
var propertyString = "Property Name: " + propertyKeyValue.Key;
var valueString = "Value : " + propertyKeyValue.Value;
}
}
I've found out that, Reflection is the answer for that as far as I could find: so here is the method I've come up with:
public static Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object item)
{
var propertyInfoList = item.GetType().GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
var list = new Dictionary<string, string>();
foreach (var propertyInfo in propertyInfoList)
{
var valueObject = propertyInfo.GetValue(item, null);
var value = valueObject != null ? valueObject.ToString() : string.Empty;
if (!string.IsNullOrEmpty(value))
{
list.Add(propertyInfo.Name, value);
}
}
return list;
}
Is this possible to do in C#?
I have POCO object here is definition:
public class Human
{
public string Name{get;set;}
public int Age{get;set;}
public int Weight{get;set;}
}
I would like to map properties of object Human to string array.
Something like this:
Human hObj = new Human{Name="Xi",Age=16,Weight=50};
Or I can have List<Human>:
string [] props = new string [COUNT OF hObj PROPERTIES];
foreach(var prop in hObj PROPERTIES)
{
props["NAME OF PROPERTIES"] = hObj PROPERTIES VALUE
}
It should be something like this:
var props = new Dictionary<string, object>();
foreach(var prop in hObj.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);)
{
props.Add(prop.Name, prop.GetValue(hObj, null));
}
see here for info on GetProperties and here for PropertyInfo
You can use reflection to get an object's properties and values:
var properties = typeof(Human).GetProperties();
IList<KeyValuePair<string, object>> propertyValues = new List<KeyValuePair<string, object>>();
foreach (var propertyInfo in properties)
{
propertyValues.Add(propertyInfo.Name, propertyInfo.GetValue(oneHuman));
}
I have a class with constant strings in it. I'd like to throw all of those strings into a drop down collection. What is the best way to do this? This is what I have now and in theory, I would think that it would be the best way to do this.
public class TestClass
{
private const string _testA = "Test A";
private const string _testB = "Test B";
public string TestA
{
get { return _testA; }
}
public string TestB
{
get { return _testB; }
}
}
public DropDownItemCollection TestCollection
{
DropDownItemCollection collection = new DropDownItemCollection();
TestClass class = new TestClass();
foreach (string testString in class)
{
DropDownItem item = new DropDownItem();
item.Description = testString;
item.Value = testString;
collection.Add(item);
}
return collection;
}
The problem is that this returns an error on the foreach: "...does not contain a public definition for GetEnumerator." I've tried to create a GetEnumerator but I've been unsuccessful and I haven't worked with GetEnumerator in the past.
Any help is greatly appreciated!
A little late but wouldn't this be a better solution?
http://weblogs.asp.net/whaggard/archive/2003/02/20/2708.aspx
private FieldInfo[] GetConstants(System.Type type)
{
ArrayList constants = new ArrayList();
FieldInfo[] fieldInfos = type.GetFields(
// Gets all public and static fields
BindingFlags.Public | BindingFlags.Static |
// This tells it to get the fields from all base types as well
BindingFlags.FlattenHierarchy);
// Go through the list and only pick out the constants
foreach(FieldInfo fi in fieldInfos)
// IsLiteral determines if its value is written at
// compile time and not changeable
// IsInitOnly determine if the field can be set
// in the body of the constructor
// for C# a field which is readonly keyword would have both true
// but a const field would have only IsLiteral equal to true
if(fi.IsLiteral && !fi.IsInitOnly)
constants.Add(fi);
// Return an array of FieldInfos
return (FieldInfo[])constants.ToArray(typeof(FieldInfo));
}
If you need the names you can do
fi.GetValue(null)
inside the loop.
I just had the same challenge; to get all constants of my class (not properties!). Based on the most popular answer (for properties) and John's answer (for constants) I wrote this. I tested it and it works well.
private List<string> lstOfConstants= new List<string>();
foreach (var constant in typeof(TestClass).GetFields())
{
if (constant.IsLiteral && !constant.IsInitOnly)
{
lstOfConstants.Add((string)constant.GetValue(null));
}
}
You could implement a method that yields the strings:
public Ienumerable<string> GetStrings(){
yield return TestA;
yield return TestB;
}
Else you should look into reflection to return the properties that are static and string and then get the values by calling them.
Regards GJ
You could use reflection to loop through all the properties:
public DropDownItemCollection TestCollection
{
var collection = new DropDownItemCollection();
var instance = new TestClass();
foreach (var prop in typeof(TestClass).GetProperties())
{
if (prop.CanRead)
{
var value = prop.GetValue(instance, null) as string;
var item = new DropDownItem();
item.Description = value;
item.Value = value;
collection.Add(item);
}
}
return collection;
}
You can use reflection to loop trought the class properties:
var instance = new TestClass();
foreach(PropertyInfo pi in typeof(TestClass))
{
var val = pi.GetValue(instance,null);
}
You need to use reflection to get name of each String from your custom type, and then also/optionally get the value of each one of those Strings...
Something like this:
TestClass theClass = new TestClass();
foreach (PropertyInfo property in theClass.GetType().GetProperties())
{
Console.WriteLine(property.Name);
Console.WriteLine(property.GetValue(theClass, null));
}