below is the Enum from which i need to populate object list
public enum Scope
{
[Description("Organization")]
Organization = 100,
[Description("Organization#Unit")]
Organization_Unit = 200,
[Description("Organization#Unit#User")]
Organization_Unit_User = 300
}
I have to create object list from this Enum
Object skeleton will be like below
public class ScopeKVP {
public string key {get;set;}
public int value {get;set;}
}
At the end I need below list of object from enum in which description of each enum should be save in key property of object and value of enum should be saved in value property of object like below
var scopeKvp = new List<ScopeKVP> {
new ScopeKVP {key= 100,value="Organization"},
new ScopeKVP {key= 200,value="Organization#Unit"},
new ScopeKVP {key= 300,value="Organization#Unit#User"}
}
This is what you need to do:
Use reflection to get the information about the enum, its fields
Loop the fields
Take their value with GetValue method
Take the attribute Description's description, which is what you passed to
its constructor
Create the object of type ScopeKVP and add it to
the result list
Code:
Type enumType = typeof(Scope);
FieldInfo[] fields = enumType.GetFields();
List<ScopeKVP> scopeKvp = new List<ScopeKVP>();
foreach (FieldInfo field in fields)
{
if (field.IsLiteral)
{
DescriptionAttribute descAttr = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));
ScopeKVP item = new ScopeKVP()
{
key = descAttr.Description,
value = (int)field.GetValue(null)
};
scopeKvp.Add(item);
}
}
// scopeKvp is what you need
P.S. like the comments above state, you have some mismatch for key which is string and you expect integer. I guess it is a typo.
Related
I have a generic object containing a list with objects, which I like to access. By using
object sourceValue = new List<tab> {new tab()};
PropertyInfo[] sourcePropertyInfo = sourceValue.GetType().GetProperties();
//First field of PropertyInfo is the list, second is a Raw instance
object result = sourcePropertyInfo[0].GetValue(sourceValue, null);
Where the tab object looks like this:
public partial class tab
{
public long TabId { get; set; }
public string Title { get; set; }
}
Here I would like to access the list throught the result variable but it results in result = 0, which is an integer. Most likley it takes the count property from the list. How can I access the values in the objects in the list (of type tab)?
Note, I can not access or change the type of the object sourceValue.
You are getting properties of list type, not the type of elements.
foreach (object element in (sourceValue as IEnumerable ?? Enumerable.Empty<object>()))
{
var type = element.GetType();
var props = type.GetProperties();
object result = props.First().GetValue(element, null);
}
Note: this can be optimized :)
I'm trying to build some objects based on properties coming from another object. The class of the objects I need to build is
public class Data
{
public string Attribute { get; set; }
public string Value{ get; set; }
}
And the attribute will be the name of the property (and the value its value)
So I was trying to use Expressions trees to make a method that I can use for avoiding hard coding that attribute
Up to the moment I came to these couple of methods, based on a couple of posts I was reading on the net
public static string GetName<T>(Expression<Func<T>> e)
{
var member = (MemberExpression)e.Body;
return member.Member.Name;
}
public static Data BuildData<T>(Expression<Func<T>> e, appDetailCategory category)
{
var member = (MemberExpression)e.Body;
Expression strExpr = member.Expression;
var name = member.Member.Name;
var value = Expression.Lambda<Func<string>>(strExpr).Compile()();
return new Data
{
Attribute = name,
Value = value
};
}
But the line I'm trying to set the value raises an exception:
Expression of type 'AutomapperTest.Program+DecisionRequest' cannot be used for return type 'System.String'
I'm pretty sure this message it's supposed to make the error obvious but it's not for me
UPDATE:
I'm calling it this way
private static Data[] GetApplicatonDetailsFromRequest(DecisionRequest request)
{
BuildData(() => request.PubID)
//...
}
Must be member, not member.Expression.
public static Data BuildData<T>(Expression<Func<T>> e, appDetailCategory category)
{
var member = (MemberExpression)e.Body;
var name = member.Member.Name;
var value = Expression.Lambda<Func<string>>(member).Compile()();
return new Data
{
Attribute = name,
Value = value
};
}
It looks like your problem is that the type of PubID isn't a string. You've got two options, either change Data to store the value as an object or call ToString on the value returned from the property and store it. For example:
public static Data BuildData<T>(Expression<Func<T>> e)
{
var member = (MemberExpression)e.Body;
var name = member.Member.Name;
Func<T> getPropertyValue=e.Compile();
object value = getPropertyValue();
return new Data
{
Attribute = name,
Value = value.ToString()
};
}
Note that to get the value you can just compile the Func expression.
I have a List that I am iterating through.
Inside the List<> are Argument classes which contain two properties 'PropertyName' and 'Value'
What I need to do is iterate through the collection of Arguments and assign the Value of that Argument to the Property (with the same name as current Argument) of a different class.
Example:
Argument:
PropertyName: ClientID
Value: 1234
Members Class:
ClientID = {Argument Value here}
I hope this makes sense. I have a way of doing it, hard coding the properties of my class and matching it up with the Argument list.
Something like:
foreach(var arg in List<Argument>)
{
Members.ClientID = arg.Find(x => compareName(x, "ClientID")).Value;
//where compareName just does a simple string.Compare
}
But what would the BEST way be for something like this?
EDIT: Sorry about this guys and thanks for the replies so far. Here is what I didn't mention and might make a difference.
Each argument is a different property for the same class. I am iterating through the List and each one in there will be for the same Members class I have to populate.
I wanted to mention this because im thinking in the foreach I might have to use a switch to determine what 'PropertyName' I have for that Argument. ClientID is one of them but I believe there are 14 total properties in the Members class that need populated from the Collection.
Does that change things?
Thanks again
public object this[string propertyName]
{
get
{
Type myType = typeof(UserConfiguration);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set
{
Type myType = typeof(UserConfiguration);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
Then you can get/set properties within the class using
myClassInstance["ClientId"] = myValue;
If I understand what you're asking, perhaps something like this will work for you:
var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value);
Members.ClientID = argDict["ClientID"];
...
If you need to do some special comparison on the keys you can provide the dictionary it's own IEqualityComparer. For example, this will make sure that the keys are treated case-insensitively:
var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value,
StringComparer.OrdinalIgnoreCase);
This will work fine as long as the arguments list contains all the values you need. If some arguments might be missing, you'd have to do something like this:
if (argDict.ContainsKey("ClientID")) {
Members.ClientID = argDict["ClientID"];
}
Or possibly something like this:
Members.ClientID = argDict.ContainsKey("ClientID") ? argDict["ClientID"] : "DefaultValue";
I think that your basic intent is to set the value of a property on a target object based on the property name. Since you did not provide the Argument class I will assume it is defined like this:
public class Argument
{
public string PropertyName{get; set;}
public object PropertyValue{get;set;}
}
Further assume you have the class Blah defined like this:
public class Blah
{
public string AString{get; set;}
public int AnInt{get; set;}
public DirectoryInfo ADirInfo{get; set;}
}
If you wish to assign to the properties of a Blah object based on the values in List<Argument> you can do so like this:
List<Argument> arguments = new List<Argument>
{
new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
new Argument(){PropertyName = "ADirInfo", PropertyValue = new DirectoryInfo(#"c:\logs")}
};
Blah b = new Blah();
Type blahType = b.GetType();
foreach(Argument arg in arguments)
{
PropertyInfo prop = blahType.GetProperty(arg.PropertyName);
// If prop == null then GetProperty() couldn't find a property by that name. Either it doesn't exist, it's not public, or it's defined on a parent class
if(prop != null)
{
prop.SetValue(b, arg.PropertyValue);
}
}
This depends on the objects stored in Argument.PropertyValue having the same type as the property of Blah referred to by Argument.PropertyName (or there must be an implicit type conversion available). For example, if you alter the List<Argument> as follows:
List<Argument> arguments = new List<Argument>
{
new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
new Argument(){PropertyName = "ADirInfo", PropertyValue = "foo"}
};
you will now get an exception when attempting to assign to Blah.ADirInfo: Object of type 'System.String' cannot be converted to type 'System.IO.DirectoryInfo'
I have the below scenario
public class TestData
{
public TestEnum EnumTestData{get;set;}
}
public Enum TestEnum
{
Test1,Test2,Test3
}
I have another class which traverse through my TestData class for all properties. Depending on the property type it will generate random data for it. Now when my propertyType is Enum type, How can I know which type of enum it is and how to get either Test1, Test2 or Test3 as my output?
You can get a list of all properties using the Type.GetProperties method:
var targetType = typeof(TestData);
var properties = targetType.GetProperties();
Then check whether it's an Enum type by checking the PropertyInfo.PropertyType and Type.IsEnum properties:
foreach(var prop in properties)
{
if (prop.PropertyType.IsEnum)
{
...
}
}
Finally get a random value using the Enum.GetValues method:
var random = new Random();
...
var values = Enum.GetValues(prop.PropertyType);
var randomValue = ((IList)values)[random.Next(values.Length)];
You can just .ToString() the EnumTestData property, like this:
var test = new TestData();
test.EnumTestData = TestEnum.Test1;
var dummy = test.EnumTestData.ToString();
Note: dummy will be "Test1".
Not entirely sure what you're asking, but this is how you would compare and get the string value of an enum:
var td = new TestData();
// compare
if (td.EnumTestData == TestEnum.Test1)
{
// Will output "Test1"
Console.WriteLine(td.EnumTestData.ToString());
}
Also, I'm sure it's just a typo but it's enum not Enum:
public enum TestEnum
{
Test1,Test2,Test3
}
Please have a look at below code.
Issue is at following loc.
MyClassExample obj2 = lstObjectCollection[0] as type;
I want to type cast an object of list to its type. But type will be given at runtime.
How can we cast an object, knowing its type at runtime?
class RTTIClass
{
public void creatClass()
{
// Orignal object
MyClassExample obj1 = new MyClassExample {NUMBER1 =5 };
// Saving type of original object.
Type type = typeof(MyClassExample);
// Creating a list.
List<object> lstObjectCollection = new List<object>();
// Saving new object to list.
lstObjectCollection.Add(CreateDuplicateObject(obj1));
// Trying to cast saved object to its type.. But i want to check its RTTI with type and not by tightly coupled classname.
// How can we achive this.
MyClassExample obj2 = lstObjectCollection[0] as type;
}
public object CreateDuplicateObject(object originalObject)
{
//create new instance of the object
object newObject = Activator.CreateInstance(originalObject.GetType());
//get list of all properties
var properties = originalObject.GetType().GetProperties();
//loop through each property
foreach (var property in properties)
{
//set the value for property
property.SetValue(newObject, property.GetValue(originalObject, null), null);
}
//get list of all fields
var fields = originalObject.GetType().GetFields();
//loop through each field
foreach (var field in fields)
{
//set the value for field
field.SetValue(newObject, field.GetValue(originalObject));
}
// return the newly created object with all the properties and fields values copied from original object
return newObject;
}
}
class MyClassExample
{
public int NUMBER1 {get; set;}
public int NUMBER2{get; set;}
public int number3;
public int number4;
}
The pattern I normally use is the is operator which will tell whether your object is a particular type. This will work if you already kinda sorta know which objects you will be using
Object myObject
if(myObject is Obj1)
// do obj1 stuff
else if(myObject is Obj2)
// do stuff with obj2
I've never had it come up where i had to operate on more than a handful of different types and treat them all specially, so this is what i normally do.
You can easily get all the objects of a certain type in the list using the OfType<T> extension method:
lstObjectCollection.OfType<MyClassExample>()
If the type is only known at runtime, you can do this:
lstObjectCollection.Where(o => o.GetType() == type)