I have 3 generict type list.
List<Contact> = new List<Contact>();
List<Address> = new List<Address>();
List<Document> = new List<Document>();
And save it on a variable with type object. Now i nedd do Cast Back to List to perfom a foreach, some like this:
List<Contact> = (List<Contact>)obj;
But obj content change every time, and i have some like this:
List<???> = (List<???>)obj;
I have another variable holding current obj Type:
Type t = typeof(obj);
Can i do some thing like that??:
List<t> = (List<t>)obj;
Obs: I no the current type in the list but i need to cast , and i dont now another form instead:
List<Contact> = new List<Contact>();
Lots of trial and error gave me this on SL 5 but it should also work on a regular C#. You also need to add LINQ to your using list for the last half to work.
List<object> myAnythingList = (value as IEnumerable<object>).Cast<object>().ToList()
Enjoy!
What a sticky problem. Try this:
List<Contact> c = null;
List<Address> a = null;
List<Document> d = null;
object o = GetObject();
c = o as List<Contact>;
a = o as List<Address>;
d = o as List<Document>;
Between c, a, and d, there's 2 nulls and 1 non-null, or 3 nulls.
Take 2:
object o = GetObject();
IEnumerable e = o as IEnumerable;
IEnumerable<Contact> c = e.OfType<Contact>();
IEnumerable<Address> a = e.OfType<Address>();
IEnumerable<Document> d = e.OfType<Document>();
I had the same problem and solved it by looking at the purpose of the casted objects. Do you really need to cast it to the specific (closed) generic types? In my case the (open) generic type had an interface which I used to cast it to.
var list = obj as IUsefulInterface;
list.MethodThatIAmInterestedIn();
I had this problem when writing a Validation Attribute where I received an object from the ValidationContext and knew that it needed to be a list, but not what it was a list of. It threw an exception when I tried to cast it as IEnumerable<object> but it could be cast as IEnumerable which then allowed the .Cast<object>() via linq.
In the end what worked was:
var enumerable = listObject as IEnumerable;
var list = enumerable.Cast<object>().ToList();
A general solution like this (to instantiate a type with a generic parameter based on a System.Type object) is not possible. If you're really just dealing with these three types, though, then you're in luck because it's pretty easy:
Type t = typeof(obj);
if (t == typeof(List<Contact>)) {
var contactList = (List<Contact>)obj;
// do stuff with contactList
} else if (t == typeof(List<Address>)) {
var addressList = (List<Address>)obj;
// do stuff with addressList
} else if (t == typeof(List<Document>)) {
var documentList = (List<Document>)obj;
// do stuff with documentList
}
No, you can't cast without going around corners (this is: reflection), generic type parameters have to be known at compile time. You can of course do something like this:
content.Where(o => o is type).ToList().Foreach(stuff);
I ran into same problem - I have a collection which data type is only known at run time and I can't cast it to anything. None of the solutions above worked. Finally I solved it by serializing to JSON and de-serializing back. Of course it's not ideal, but may help someone.
string jsonString = JsonConvert.SerializeObject(myObject);
jsonString = "{ values:" + jsonString + "}";
JObject j = JObject.Parse(jsonString);
//now we can iterate over the list
foreach (var x in j["values"])
{
string name = x.ToString();
...
}
Employee employee=new Employee();
List<Employee> emplist=new();
emplist.Add(employee);
This is correct way
Thank you
You might need to do:
if(object is List)
{
list = (List)object
}
Related
I have a
List<object> list = new List<object>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
}
I need to select just items where level == 1
i tried
list = list.where(item => item.level == 1);
but i get an error
'object' does not contain a definition for 'level' and no extension method 'level' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
i know that the compiler can get the type so he can know what it is "level".
how can i achieve this kind of select, without to define a class ?
You have two ways of fixing this:
Use a List<dynamic> instead of a List<object>. This will disable type checks. Drawback: This will disable type checks. :-)
Let the compiler infer the correct type of your list. To do this, have your data layer return a DataTable instead of a DataReader and then use LINQ to create the list:
var myList = (from drow in myDataTable.AsEnumerable()
select new {
kablanim = drow["arrK_Title"].ToString(),
total = drow["arrTotal"].ToString(),
...
}).ToList();
I can't see why you don't just make a concrete class:
public class Foo
{
public string Title { get; set; }
public string Path { get; set; }
// etc, etc
}
Then
List<Foo> list = new List<Foo>();
while (myReader.Read())
{
string arrKablan = myReader["arrK_Title"].ToString();
string arrTotal = myReader["arrTotal"].ToString();
string _title = myReader["MF_Title"].ToString();
string _path = myReader["MF_Path"].ToString();
int _level = Convert.ToInt32(myReader["MF_Level"].ToString());
list.Add(new Foo { Title = _title, Path = _path, /* etc, etc */ });
}
then you call becomes
list = list.Where(item => item.Level == 1).ToList();
(Note the additional ToList call required to make the list assignment valid)
Just for completeness, you can also do this. Create a function to get a value from any object using reflection:
private T GetValue<T>(object obj, string property)
{
return (T)obj.GetType()
.GetProperties()
.Single(p => p.Name == property)
.GetValue(obj);
}
And call it like this:
var filteredList = list.Where(item => GetValue<int>(item, "level") == 1);
You can get value of a property on anonymous class like this:
var anon = new { Level = "level", Time = DateTime.Now };
Type type = anon.GetType();
var props = type.GetProperties();
foreach (var propertyInfo in props)
{
if (propertyInfo.Name == "Level")
{
var x =propertyInfo.GetValue(anon);
}
}
I'm not sure if it is the best way to achieve that, but it is certainly possible.
You are adding object of anonymous class to the list. You can refer to this anonymous class field only inside the method you've defined it in and you should probably avoid adding it to the list, because there is now other way other then reflection or dynamic to access field of theese objects.
For example, you can access one of the elements like this:
var list = new List();
list.Add(new { field1 = "a", field2 = 2 });
list.Add(new { field1 = "b", field2 = 3 });
list.Add(new { field1 = "c", field2 = 4 });
dynamic o = list[1];
Console.WriteLine(o.field1);
Console.WriteLine(o.field2);
But you should be aware, that dynamic feature has a big overhead on every member access.
If you really want to use lambdas, you can rewrite
list = list.where(item => item.level == 1);
like this
var filtered = list.Where(item =>
{
dynamic ditem = item;
return ditem.Level == 1;
});
but this is a bad approach.
The other approach is to use reflection and rewrite this lambda like this
var filtered = list.Where(item =>
{
var field = item.GetType().GetField("level");
return (int)field.GetValue(item) == 1;
});
This is better than using dynamic because it has a smaller overhead, but can still be very costly.
Also it would probably be better to cache FieldInfo object outside of loop if your anonymous objects have same type. It can be done like this
var field = list.First().GetType().GetField("level");
var filtered = list.Where(item => (int)field.GetValue(item) == 1);
For performance reasons, Linq depends on metadata being available at compile time. By explicitly declaring List<object> you have typed the elements of this list as object which does not have a member level.
If you want to use Linq like this you have two options.
Declare a class with a level member and use it to type the collection
Declare an interface with a level member and use it to cast in the lambda expression
Option 1 is the preferred approach. Normally Linq is used with a database and the classes are generated by Visual Studio directly from the database. This is why nobody complains about the need for classes to supply metadata.
The following line creates anonymous class.
new { title = _title, path = _path, kablanim = arrKablan, total = arrTotal, level = _level });
You can't cast then your objects to anything meaningfull.
Objects don't have those properties.
You have to create a class by your own and use it.
I have a problem in creating dynamic objects. Please find the below code,
List<object> membersList = new List<object>();
foreach(var members in activityMembers){
dynamic myObject = new System.Dynamic.ExpandoObject();
myObject.MemberNumber = members.MemberNumber;
myObject.MemberName = members.Name;
foreach (var activity in members.ActivityList)
{
myObject.[activity.ActivityName] = activity.Minutes;
}
membersList.Add(myObject);
}
there inside the second foreach loop, i need to generate the properties to all activities. for example if there are 4 activities in members.ActivityList, then 4 properties needs to be generated for object.
myObject.Activity1 = 10;
myObject.Activity2 = 20;
myObject.Activity3 = 30;
myObject.Activity4 = 40;
How can i do this? What i did wrong here?
Regards,
Karthik.
Remove the . when you are indexing the object i.e. change
myObject.[activity.ActivityName] = activityMinutes;
to
myObject[activity.ActivityName] = activity.Minutes;
Actually this won't solve your problem straight away, it will compile fine but when you attempt to run it will throw a RuntimeBinderException as you can't index into a ExpandoObject directly. You need to cast it as a dictionary before iterating (that's effectively what it is) e.g.
var dict = (IDictionary<string, object>)myObject;
...
dict[activity.ActivityName] = activity.Minutes;
I suspect you need to treat the ExpandoObject as a dictionary for that part:
IDictionary<string, object> dictionary = myObject;
foreach (var activity in members.ActivityList)
{
dictionary[activity.ActivityName] = activity.Minutes;
}
That's the way of assigning properties to an ExpandoObject when you don't know the property name at compile-time.
For example
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
later in the code:
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1; // I make a copy of namelist1 to namelist2
So, from this point I would like to keep adding element or making changes in name_list2 without affecting name_list1. How do I do that?
name_list2 = new List<string>(name_list1);
This will clone the list.
Edit: This solution only works for primitive types. For objects, see other responses below.
Another Options is : Deep Cloning
public static T DeepCopy<T>(T item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
T result = (T)formatter.Deserialize(stream);
stream.Close();
return result;
}
so,
you can use :
name_list2 = DeepCopy<List<string>>(name_list1);
OR:
name_list2 = DeepCopy(name_list1);
will also work.
For Primitive Types you can do this:
List<string> CopyList = new List<string>(OriginalList);
For non-primitve/user-difined types you can do this:
List<Person> CopyList = new List<Person>();
foreach(var item in OriginalList)
{
CopyList.Add(new Person {
Name = item.Name,
Address = item.Address
});
}
name_list2 = new List<string>(name_list1); // Clone list into a different object
At this point, the two lists are different objects. You can add items to list2 without affecting list1
The problem is the assignment. Until the assignment name_list2 = name_list1;, you have two different List objects on the heap pointed to by the variables name_list1 and name_list2. You fill up name_list1, which is fine. But the assignment says, "make name_list2 point to the same object on the heap as name_list1." The List that name_list2 used to point to is no longer accessible and will be garbage collected. What you really want is to copy the contents of name_list1 into name_list2. You can do this with List.AddRange. Note that this will result in a "shallow" copy, which is fine for the example you cite, where the list contents are strings, but may not be what you want when the list members are more complex objects. It all depends on your needs.
Based on #Mrunal answer I created an extension method:
public static T Clone<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (source == null)
{
return default;
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
And you can call it like this:
L2 = L1.Select(x => x.Clone()).ToList();
I like linq for this...
If list elements are primitives or structures then...
L2 = L1.ToList()
If list elements are classes then...
L2 = L1.Select(x => x.Copy()).ToList();
Where Copy could simply be a shallow copy exposure of MemberWiseClone, or it could be some implementation of a deep copy.
I prefer Json converter method to serialize and deserialize, this way you don't have to mark the classes for serialization, especially you have numerous child classes.
https://www.newtonsoft.com/json/help/html/SerializingJSON.htm
Here is an alternative solution:
List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2.AddRange(name_list1.ToArray());
The ToArray() method copies 'name_list1' to a new array, which we then add to name_list2 via the AddRange() method.
For primitive types:
List ClonedList = new list(OriginalList);
For non-primitive/User Defined types:
We need to perform a deep copy:
Deep Copy is used to make a complete deep copy of the internal reference types, for this we need to configure the object returned by MemberwiseClone().
Step1- In your class inherit from ICloneable:
public class MyClass:ICloneable
Step2- Implement method
public MyClass Clone()
{
MyClass MyClassObj =new MyClass();
MyClassObj.Property1 = this.Property1;
.
.
MyClassObj.Property_N = this.Property_N;
return MyClass;
}
Step3- now clone your List
List<MyClass> MyClassClone = new List<MyClass>();
for(i=0; i<Count; i++)
{
MyClassClone.Add(OriginalClaaObj[i].Clone());
}
This will make deep copy of each item of the object.
None of the above solutions worked for me when using lists of class objects.
This can be used for copying any object to another object with shared property names.
public static void ObjectToObject(object source, object destination)
{
// Purpose : Use reflection to set property values of objects that share the same property names.
Type s = source.GetType();
Type d = destination.GetType();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var objSourceProperties = s.GetProperties(flags);
var objDestinationProperties = d.GetProperties(flags);
var propertyNames = objSourceProperties
.Select(c => c.Name)
.ToList();
foreach (var properties in objDestinationProperties.Where(properties => propertyNames.Contains(properties.Name)))
{
try
{
PropertyInfo piSource = source.GetType().GetProperty(properties.Name);
properties.SetValue(destination, piSource.GetValue(source, null), null);
}
catch (Exception ex)
{
throw;
}
}
}
public static List<T> CopyList<T>(this List<T> lst)
{
List<T> lstCopy = new List<T>();
foreach (var item in lst)
{
var instanceOfT = Activator.CreateInstance<T>();
ObjectToObject(item, instanceOfT);
lstCopy.Add(instanceOfT);
}
return lstCopy;
}
For lists use this:
list2 = list1.CopyList();
If both the lists are of the same complex type then you can do something like below:-
SomeClass List2 = new List();
List1.ForEach(u => List2.Add(u));
What I am doing is to loop through each element of List1 and keep adding it to List2.
I believe this is the shortest way to do it.
While it could be potential performance-threat solution, but it would copy the values property-by-property eloquently.
using Newstonsoft.Json;
ClassA classA = new ClassA();
ClassA classACopyWithoutReference = JsonConvert.DeserializeObject<ClassA>(JsonConvert.SerializeObject(classA));
this solution works For complex objects (Replace T with name of your Type):
list2 = list1.Concat(new List<T> { object }).ToList();
or:
list2 = list1.ToArray().Append(object).ToList()
You can clone the complex object by serialize and deserialize it, it will remove you object reference and create new object without reference
using Newstonsoft.Json;
List<string> name_list1 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");
name_list2 = name_list1;
List<string> name_list2 = JsonConvert.DeserializeObject<List<string>>
(JsonConvert.SerializeObject(name_list1)); // Ii make a copy of namelist1 to namelist2
this is working for me using LINQ...
lst1= lst2.ToList();
I have a collection of custom objects, dependents. The custom object has about 70 properties. I want to extract just one property, the membernumber. I have the following code, where I am extracting the membernumbers and creating another list:
var memberIDs = (from d in dependents
select new
{
d.MemberNum
});
foreach(var id in memberIDs)
{
string idValue = id.ToString();
}
The problem is that idValue comes as "{ MemberNum = 20044782604 }" instead of just the "20044782604". Please let me know how to resolve it.
Thanks
That's because you are creating a new anonymous type with the MemberNum as a property. Just select it instead.
var memberIDs = from d in dependents
select d.MemberNum;
This will yield an IEnumerable<int> instead of an IEnumerable<AnonymousType> (assuming MemberNum is of type int).
I have a 2 lists of an object type:
List<MyClass> list1;
List<MyClass> list2;
What is the best way (performance and clean code) to extract differences in data between these two List?
I mean get objects that is added, deleted, or changed (and the change)?
Try Except with Union, but you'll need to do it for both in order to find differences in both.
var exceptions = list1.Except(list2).Union(list2.Except(list1)).ToList();
OR as a Linq alternative, there could be a much faster approach: HashSet.SymmetricExceptWith():
var exceptions = new HashSet(list1);
exceptions.SymmetricExceptWith(list2);
IEnumerable<string> differenceQuery = list1.Except(list2);
http://msdn.microsoft.com/en-us/library/bb397894.aspx
You may use FindAll to get the result you want, even you don't have IEquatable or IComparable implemented in your MyClass. Here is one example:
List<MyClass> interetedList = list1.FindAll(delegate(MyClass item1) {
MyClass found = list2.Find(delegate(MyClass item2) {
return item2.propertyA == item1.propertyA ...;
}
return found != null;
});
In the same way, you can get your interested items from list2 by comparing to list1.
This strategy may get your "changed" items as well.
One way to get items that are either in list1 or in list2 but not in both would be:
var common = list1.Intersect(list2);
var exceptions = list1.Except(common).Concat(list2.Except(common));
Try this for objects comparison and loop around it for List<T>
public static void GetPropertyChanges<T>(this T oldObj, T newObj)
{
Type type = typeof(T);
foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
object selfValue = type.GetProperty(pi.Name).GetValue(oldObj, null);
object toValue = type.GetProperty(pi.Name).GetValue(newObj, null);
if (selfValue != null && toValue != null)
{
if (selfValue.ToString() != toValue.ToString())
{
//do your code
}
}
}
}