convert List<List<object>> to IList<IList<object>> - c#

I have written a method which is
public List<List<object>> Fetch(string data),
inside I create
List<List<object>> p = new List<List<object>>();
my boss now wants to return a IList<IList<object>> instead of List<List<object>> ie
public IList<IList<object>> Fetch(string data),
so when I try do
return (IList<IList<object>>) p; //throws an exception
How do I convert
List<List<object>> to IList<IList<object>> and back to List<List<object>>

You can't perform that conversion via straight casting - it wouldn't be safe. Instead, you should use:
IList<IList<object>> ret = new List<IList<object>>();
Then for each "sublist" you can use:
// Or whatever
ret.Add(new List<object>());
Finally, just return ret.
You could use LINQ to perform the conversion of your existing List<List<object>> when you return it - but it would be better to just create a more appropriate type to start with, as shown above.
To understand why some of the existing answers are wrong, suppose you could do this:
IList<IList<object>> p = new List<List<object>>();
Then this would be valid:
List<List<object>> listOfLists = new List<List<object>>();
IList<IList<object>> p = listOfLists;
p.Add(new object[]);
List<object> list = p[0];
But p[0] is a reference to an object[], not a List<object>... our supposedly type-safe code doesn't look as safe any more...
Fortunately, IList<T> is invariant to prevent exactly this problem.

You would have to declare your list as
IList<IList<object>> list = new List<IList<object>>(); // Works!
This works, because only the outer list is created in the first place. You can then insert individual items that are compatible with IList<object>:
list.Add(new List<object>());
list.Add(new object[10]);

var myOriginalList = new List<List<Object>>();
var converted = ((IList<IList<Object>>)myOriginalList.Cast<IList<Object>>().ToList()); // EDIT: Added .ToList() here
You shouldn't need to convert back- you can do just about anything on IList that you could on List.

You need to change the declaration of the result variable from List<List<object> to IList<IList<object>>
Which you can instantiate against List<IList<object>>
And each item in the result can be of type List<object>
static IList<IList<object>> Test()
{
IList<IList<object>> result = new List<IList<object>>();
var item = new List<object>() { "one", "two", "three" };
result.Add(item);
return result;
}

public IList<IList<object>> Fetch(string data)
{
IList<IList<object>> p = new List<IList<object>>();
// add your stuff here
return p;
}

List<T> and IList<T> do not support covariance. So this does not compile:
List<List<string>> list = new List<IList<string>>(); // DOES NOT COMPILE!!!!!

Related

How can I cast a list to an observablecollection in c#?

I have a List that I want to cast to an ObservableCollection, this is my code
var list = Models.Lands.FromJson(responce.Result.ToString());
this.Lands = new ObservableCollection<Land>( list );
FromJson returns me a List<Models.Land>, and this.Lands is an ObservableCollection<Models.Land>.
new ObservableCollection<Models.Land>( list ) gives me the following error:
cannot convert from System.Collections.Generic.List<> to
System.Collections.Generic.IEnumerable<>,
I thought that the constructor was overloaded for a List<> object.
Try using the nongeneric var keyword.
List<Land> list =Models.Lands.FromJson(responce.Result.ToString());
var collection = new ObservableCollection<Land>(list);
I think you can do something like below to avoid your problem but still using a single line of code:
this.Lands = new ObservableCollection<Land>( list.ToArray<Land>());
but I'm not sure if that's an efficient way to do that.
Works in my browser: https://dotnetfiddle.net/VVB8YY
public static void Main()
{
var list = new List<String>{"a", "b", "c"};
var collection = new ObservableCollection<string>(list);
foreach (var value in collection)
{
Console.WriteLine(value);
}
Console.WriteLine("Hello World");
}

How can I add an item to a list and return a new list

I was asked this question today:
How can I add an item to a list and return that list back?
The code for List<T>.Add(T) returns void. So you can't do something like this:
var list = new List<string>{"item1","item2"};
var newList = list.Add("item3");
This is related to using AutoMapper, although that part isn't particularly important.
One option is Linq, with Concat:
var list = new List<string>{"item1", "item2"};
var newList = list.Concat(new[] { "item3" }).ToList();
In typical Linq fashion, list stays the same, and newList contains all the items from list as well as the items in the new list, in this case just "item3".
You can skip the .ToList() to keep the IEnumerable<string> result if that fits your use case.
If you find yourself doing this often with individual items, you can use something like this extension method to pass them without the new[] { ... } syntax:
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> source, params T[] items)
{
return source.Concat(items);
}
Because of the params array the earlier example becomes:
var list = new List<string>{"item1", "item2"};
var newList = list.ConcatItems("item3").ToList();
Make sure not to mix this up with Union, which removes duplicate items. (Searching for those duplicates is overhead that you probably don't want!)
The answer to this question was relatively simple:
var list = new List<string>(new List<string>{"item1","item2"}){"item3"};
List<T>() has a constructor that can take in IEnumerable<T> (MSDN). Additionally, you can use the object setter to put new items into the list.
So, for a more complicated example:
var originalList = new List<string>();
originalList.Add("item1");
originalList.Add("item2");
var newList = new List<string>(originalList){"item3"};
You can simply do :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = null;
(newList = list.ToList()).Add("item3");
Or create your own extension method :
public static class Helper
{
public static List<T> MyAdd<T>(this List<T> collection, T item)
{
collection.Add(item);
return collection;
}
}
And use it :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = list.MyAdd("item3"); // same object though
List<string> newList2 = newList.ToList().MyAdd("item4").MyAdd("item5"); // different object
One property of an ImmutableList<T> (and other similar data structures from System.Collections.Immutable) is that it doesn't mutate the original list, it returns another immutable list with the added value.
So doing this:
var originalImmutable = ImmutableList<int>.Create(1, 2);
var otherImmutable = originalImmutable.Add(3);
Will result in a shallow copied new list each time you call Add.
The most readable and maintainable solution is to copy the list and then add the item:
var list = new List<string>{"item1","item2"};
var newList = list.toList();
newList.Add("item3");
Seven years have passed since the question has been asked but Enumerable class now offers Prepend and Append methods that could be used in a straightforward fashion:
var list = new List<string>{"item1","item2"};
var newList = list.Append("item3").ToList();

How to assign List<T> without it being a reference to the original List<T>?

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();

How to cast List<> in C#

How to cast two List...
I want something like that
List<Obj1> list = new List<Obj1>();
list.add(new Obj1);
List<Obj2> list2 = new List<Obj2>();
list2.add((Obj1)list[0]);
You may be interested in the Enumerable extension method Cast.
IEnumerable<Obj2> enumerable = list.Cast<Obj2>();
You can then convert to List if necessary:
var list2 = enumerable.ToList()
(This obviously assume the cast from Obj1 to Obj2 is valid: that Obj2 derives from Obj1 or that a conversion operator exists.)
I'm not sure what you are trying to do but it might be something like this
var nums = new List<int> {3,1,4,1,5,9,2,6,5};
var words = new List<string> {"Do", "not", "disturb", "my", "circles"};
words.AddRange(nums.Cast<string>());
To add a single element, your code would work, provided you fix the syntax:
List<Obj1> list = new List<Obj1>();
list.Add(new Obj1());
List<Obj2> list2 = new List<Obj2>();
list2.Add((Obj1)list[0]);
To concatenate the the whole list you can replace the last line with list2.AddRange(list.Cast<Obj1>());

Replacing ArrayList with List<> in C#

I am using extensively ArrayList and having difficulty to use this List<>. I am using the EntitySpace ORM for doing DAL stuff. This thing works nicely BUT the issue is that I have to defined List<> with type of object which is complaining that it can't convert that.
I am appreciate your help.
Original using ArrayList:
public ArrayList Get()
{
TndCustomerTendersCollection collection = new TndCustomerTendersCollection();
collection.Query
.Select
(
collection.Query.CustomerTenderID,
collection.Query.CustomerTenderID,
collection.Query.CustomerTenderCode,
collection.Query.CustomerTenderName,
collection.Query.StartDate,
collection.Query.DueDate,
collection.Query.CompleteDate,
collection.Query.DateCreated,
collection.Query.LastDateModified
)
.Where
(
collection.Query.IsActive.Equal(true)
);
ArrayList list = new ArrayList ();
foreach (TndCustomerTenders item in collection)
{
list.Add(item);
}
return list;
}
After replacing with List
public List<Tender> Get()
{
TndCustomerTendersCollection collection = new TndCustomerTendersCollection();
collection.Query
.Select
(
collection.Query.CustomerTenderID,
collection.Query.CustomerTenderID,
collection.Query.CustomerTenderCode,
collection.Query.CustomerTenderName,
collection.Query.StartDate,
collection.Query.DueDate,
collection.Query.CompleteDate,
collection.Query.DateCreated,
collection.Query.LastDateModified
)
.Where
(
collection.Query.IsActive.Equal(true)
);
// HOW DO CONVERT THAT TO THAT LIST
List<Tender> list = new List<Tender>();
foreach (TndCustomerTenders item in collection)
{
list.Add(item);
}
return list;
}
TndCustomerTenders and Tender are two different types.
You need to either explicitly convert from TndCustomerTenders to Tender, or you need to define an implicit conversion.
List<Tender> list = new List<Tender>();
foreach (TndCustomerTenders item in collection)
{
//assumes conversion via constructor
list.Add(new Tender(item));
}
or
List<Tender> list = new List<Tender>();
foreach (TndCustomerTenders item in collection)
{
Tender t = new Tender() { foo = item.foo, bar = item.bar };
list.Add(t);
}
return collection.ToList<Tender>();
Change
public List<Tender> Get()
to
public List<TndCustomerTenders> Get()
and change
List<Tender> list = new List<Tender>();
to
List<TndCustomerTenders> list = new List<TndCustomerTenders>();
Or if you are using the latest framework,
var list = new List<TndCustomerTenders>();
Is this what you want?
.Where(collection.Query.IsActive.Equal(true)).Cast<Tender>().ToList()

Categories

Resources