c# - how to access a list inside a generic object - c#

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 :)

Related

How to convert dynamic or object to strongly typed objects in C#

I have a Class in which below properties are there.
Public class Classifields
{
public int ID {get;set;}
public Name {get; set;}
public Type {get; set;}
}
The above object is used as child object in an parent.
So the Parent Object will contain the Id of this Classifields.
For some purpose I am taking all the properties of the parent class with the related objects loaded into it, Which means Parent and child object also loaded.
I am taking the properties in this way like below.
PropertyInfo[] allProps = typeof(T).GetProperties();
return allProps;
So the returned properties will have some time the single Classifields or some times multiple classifields.
I take value like below
var newValue = prop.GetValue(model, null);
For the Classifields list property , I am checking for property fullname contains "Classifields" or not and passing the list of classifields or single Classfields as dynamic object to process and take the Name with comma separated value from the list or single item.
When it is multiple entry I try to use IList of object to typecast the dynamic it works correctly but when it comes as single object it fails because it is not IList.
At the same time I tried with foreach Classifields but that also not works.
if(val.FullName.Contains("Classifields"))
{
old = (oldV != null) ? GetNames(oldV) : null;
new = (newV != null) ? GetNames(newV) : null;
}
public string GetNames(dynamic stringDatatoProcess)
{
if (stringDatatoProcess== null)
return "";
try
{
string Names = "";
if (stringDatatoProcess!= null)
{
dynamic dynamicDog = stringDatatoProcess;
string values = string.Empty;
//IList<Classifields> classfields = dynamicDog;
StringBuilder stringvalues = new StringBuilder();
foreach(Classification classification in dynamicDog)
{
stringvalues.Append(classification.ClsName);
stringvalues.Append(",");
}
ClsNames = stringvalues.ToString().TrimEnd(',');
}
return ClsNames;
}
catch (Exception ex)
{
throw ex;
}
}
How to handle this situation because I cant check the count as well since it is dynamic object. And I am not able to count the items because it is throwing the exception while typecasting itself.

C# string to necessary type conversion

I have following situation. Lets say i receive list of string values. I have to assign those values to specific type properties in Model.
Model example:
public int ID { get; set; }
public DateTime? Date { get; set; }
There is no problem in type conversion as i get array of property types with System.reflection and use Convert.ChangeType(string value, type).
However, i can't assignt Convert.ChangeType results to model properties because it returns object not my desired type of value.
A short example of my problem:
string s1 = "1";
string s2= "11-JUN-2015";
PropertyInfo[] matDetailsProperties = Model.GetType().GetProperties();
List<Type> types = new List<Type>();
foreach(var item in Model)
{
types.Add(item.PropertyType);
}
Model.ID = Convert.ChangeType(s1, types[0]);
Model.Date = Convert.ChangeType(s2, types[1]);
This does not work as Convert.ChangeType returns object and i can't just use (dateTime)Convert.ChangeType(...), that's "dirty code" as i have model with 17 properties with different types. It would be perfect if i could use (Type[0])Convert.ChangeType(...) but it is not possible in C#
You could use reflection. How about something like this?
var prop = Model.GetType().GetProperty("ID");
var propValue = Convert.ChangeType(s1, types[0]);
if (prop != null && prop.CanWrite)
{
prop.SetValue(Model, propValue, null);
}
instead of Parse i'll suggest you use TryParse(string, out DateTime)
int tempId=default(int);
DateTime tempDate=DateTime.Min;
int.TryParse(s1,out tempId);
DateTime.TryParse(s2,out tempDate);
Model.ID = tempId;
Model.Date = tempDate;
You do not need to use Convert.ChangeType. Just use the existing parsers inside a function to create your model in a simple-to-follow fashion:
private static Model PopulateModel(IEnumerable<string> rawData)
{
return new Model
{
ID = int.Parse(rawData[0]),
Date = DateTime.Parse(rawData[1]),
...
};
}

Best way to assign property value dynamically based on the property name

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'

How to cast object at runtime, while getting type information at runtime

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)

Cast ExpandoObject to anonymous type

Can I cast ExpandoObject to anonymous type ?
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
// Here I'm populating the expandoObj with same property names/types in anonymoustype(anoObj)
// Now, how to convert this ExpandoObject to anonymoustype ?
var newObj = (typeof(anoObj)expandoObj); // This doesn't work
Added Later
// This is my entity
public class Customer
{
#region Public Properties
[ColumnAttribute(Name = "IdColumn")]
public string Id { get; set; }
[ColumnAttribute(Name = "NameColumn")]
public string Name { get; set; }
[ColumnAttribute(Name = "AddressColumn")]
public string Address { get; set; }
[ColumnAttribute(Name = "EmailColumn")]
public string Email { get; set; }
[ColumnAttribute(Name = "MobileColumn")]
public string Mobile { get; set; }
#endregion
}
// -------------------------------------------------------------------------------------
public class LookupService<TEntitySource>
{
public LookupService ()
{
}
public LookupShowable<TEntitySource, TSelection> Select<TSelection>(Expression<Func<TEntitySource, TSelection>> expression)
{
var lookupShowable = new LookupShowable<TEntitySource, TSelection>();
return lookupShowable;
}
}
public class LookupShowable<TEntitySource,TSelection>
{
public LookupShowable()
{
}
public LookupExecutable<TEntitySource, TSelection, TShow> Show<TShow>(Expression<Func<TEntitySource, TShow>> expression)
{
var lookupExecutable = new LookupExecutable<TEntitySource,TSelection,TShow>();
return lookupExecutable;
}
}
public class LookupExecutable<TEntitySource, TSelection, TShow>
{
public TSelection Execute()
{
// Here I want to create a new instance of TSelection and populate values from database and return it.
}
}
//--------------------------------------------------------------------------------------
// This is How I want to call this from front end...
var lookupService = new LookupService<Customer>();
var lookupSelection = lookupService.Select(C => new { C.Id, C.Name, C.Mobile }).Show(C => new { C.Id, C.Name}).Execute();
string sID = lookupSelection.Id;
string sName = lookupSelection.Name;
string sMobile = lookupSelection.Mobile;
Dont think about this middle part.. Purpose of it is another one...
My problem is in Execute() method in LookupExecutable class. I dont know how to create a new instance of TSelection type and assign values to it. This TSelection type is always an anonymous type..
EDIT: I think this question is a prime example of the XY problem. The correct solution doesn't need to concern itself with ExpandoObject or anonymous types, and it would be most likely wrong if it did.
You're looking at it the wrong way. You don't need to create an instance of an anonymous object, you need to invoke the code that is passed to you in an expression (which may or may not be creating an anonymous object).
If you can create an instance of TEntitySource, then that's simple: Compile() the Expression that you got in Select() and then invoke it for each instance of TEntitySource.
If you can't create TEntitySource, you could still do it by rewriting the Expression (using ExpressionVisitor), so that its input is not TEntitySource, but some type you have. But that would require some work from you.
Original answer:
No, that won't work. That's simply not how casting or anonymous types work in C#.
You can't cast between any two types and expect it to work. Either the object you're casting needs to be the type you're casting to, or one of the two types needs to specify a matching cast operator.
The fact that the target type is an anonymous type doesn't change anything (except that you can't even try to cast to an anonymous type directly, because you can't name it; the way you're using typeof() is wrong).
The fact that the source type is dynamic changes things a bit. But only in that the search for the cast operator is done at runtime, not at compile time, and you can even create the cast operator at runtime (see DynamicObject.TryCast()). But that's it, it doesn't add any “magical” cast operators.
The only way I can imagine something like this working would be if you used a variant of “cast by example” and reflection:
public T Convert<T>(ExpandoObject source, T example)
where T : class
{
IDictionary<string, object> dict = source;
var ctor = example.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T)ctor.Invoke(parameterValues);
}
You could then use it something like this:
var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });
Note that you can't actually invoke Convert() dynamically (by passing it dynamicExpando), because that would mean it would return dynamic too.
Use JavaScriptSerializer to convert the ExpandoObject to any Type as follows:
.....
dynamic myExpandoObject = new ExpandoObject();
var result = ConvertDynamic<myType>(myExpandoObject);
.....
public T ConvertDynamic<T>(IDictionary<string, object> dictionary)
{
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var obj = jsSerializer.ConvertToType<T>(dictionary);
return obj;
}
This should do the job.
here you have an object made from an ExpandoObject
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
object newObj = expandoObj;
But beware, dynamic objects are very very expensive in resource matters, and what you are asking for does not seem to have any sense. A good aproach for what you are asking in the comments supposing you have to deal with dynamic objects and you want to do something with them:
dynamic expando = new System.Dynamic.ExpandoObject();
var myObj = new Dictionary<string, object>();
myObj["myProperty"] = expando.myProperty;
Any dynamyc object is easily casted to a <string, object> typed Dicionary.
Hope that helps!

Categories

Resources