I was wondering if there was a method in which I can hold a generic list that can hold a generic list.
My issue is that I have a list that can hold either LIST A or LIST B or LIST C.
I figured out how to do this with Data types but I want this list to be able to hold classes that I create.
For example:
List<T> listA = new List<T>();
Where T is ObjectX
listA.Add(new list<Y> { new List<U>() { new List<T>() } } );
Where Y is ObjectY<br>
Where U is ObjectU
etc.
EDIT:
Let me put it into context.
I have a list of Objects called Suites
Each Suite can have a list of CaseObjects OR a list of CaseHolderObjects.
Each CaseHolder can hold a list of CaseObjects
Each Case can hold a list of ActionObjects
I think this is what you want:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace TestList
{
public class Program
{
public static void Main(string[] args)
{
//Use this syntax for a list of list of classes
List<List<Test>> test = new List<List<Test>>();
}
}
//This class is just for example.
class Test
{
//Your class code here
}
}
This is what you wanted, a list that holds any other type of list ^^
class Program
{
static void Main(string[] args)
{
Person p1 = new Person(1, "Mario");
Person p2 = new Person(2, "Franco");
Dog d1 = new Dog(1, "Fuffy");
Dog d2 = new Dog(2, "Chop");
List<Person> listP = new List<Person>();
listP.Add(p1);
listP.Add(p2);
List<Dog> listD = new List<Dog>();
listD.Add(d1);
listD.Add(d2);
List<Object> listO = new List<Object>();
listO.Add(listP);
listO.Add(listD);
}
public class Person
{
public Person(int id, string name)
{
this.id = id;
this.name = name;
}
public int id { get; set; }
public string name { get; set; }
}
public class Dog
{
public Dog(int id, string name)
{
this.id = id;
this.name = name;
}
public int id { get; set; }
public string name { get; set; }
}
}
I solved the issue. The classes in question I had them implement an empty interface. I then created a single property.
List<List<Interfaces.IMetaData>> myList = new List<List<Interfaces.IMetaData>>();
myList.Add(new List<Interfaces.IMetaData>() { new SuiteObject() { } });
myList.Add(new List<Interfaces.IMetaData>() { new CaseHolderObject() { } });
myList.Add(new List<Interfaces.IMetaData>() { new CaseObject() { } });
myList.Add(new List<Interfaces.IMetaData>() { new ActionObject() { } });
You don't need generic collection if you want to store different class in it. Try to use ArrayList (System.Collections namespace). You can add to it any object (of cource cost of performace);
For example:
ArrayList listA = new ArrayList() { 1, true, "string" };
ArrayList ListB = new ArrayList() { 2, false };
ArrayList ListC = new ArrayList() { 3, "string3" };
ListB.Add(ListC);
listA.Add(ListB);
Related
Consider:
public interface I
{
int InterfaceProperty {get;set;}
}
public class C1 : I
{
public int InterfaceProperty {get;set;}
public int Class1Property {get;set;}
}
public class C2 : I
{
public int InterfaceProperty {get;set;}
public int Class2Property {get;set;}
}
//In some other class:
public List<I> L;
void somemethod()
{
this.L = new List<I>();
this.L.Add(new C1()); //add some C1s into the list
SomeMethodToGetProperties(L);
this.L = new List<I>();
this.L.Add(new C2()); //add some C2s into the list
SomeMethodToGetProperties(L);
}
I need SomeMethodToGetProperties that gets a list of the properties for C1 or C2. ie, first call returns InterfaceProperty and Class1Property and the second call returns InterfaceProperty and Class2Property.
I can't use an object in the list, because the lists may be empty. I tried Reflection on the lists, but that only gave me the properties for the interface.
EDIT: The original way I wrote it was not valid. You can't do
this.L = new List<C1>()
You can only do something like
this.L = new List<I>();
this.L.Add(new C1());
It seems what I need may not be possible from the metadata of the list itself.
So I created a second variable to hold the type of item held in the list that I set every time I change the list contents.
This is one implementation, that scans each item in a list, and collects the item type and its properties. This is because each list might have more than one type that is inherited from the interface.
I renamed the interface and classes for clarity.
The result is
Class1
InterfaceProperty
Class1Property
Class2
InterfaceProperty
Class2Property
with code:
public interface IInterface
{
int InterfaceProperty { get; set; }
}
public class Class1 : IInterface
{
public int InterfaceProperty { get; set; }
public int Class1Property { get; set; }
}
public class Class2 : IInterface
{
public int InterfaceProperty { get; set; }
public int Class2Property { get; set; }
}
class Program
{
public static List<IInterface> list;
static void Main(string[] args)
{
list = new List<IInterface>();
list.Add(new Class1());
list.Add(new Class2());
list.Add(new Class1());
list.Add(new Class1());
list.Add(new Class2());
foreach (var itemType in GetItemTypeProperties(list))
{
Console.WriteLine(itemType.Key.Name);
foreach (var property in itemType.Single())
{
Console.WriteLine($"\t{property.Name}");
}
Console.WriteLine();
}
}
public static IEnumerable<IGrouping<Type,PropertyInfo[]>> GetItemTypeProperties<T>(List<T> list)
{
var itemProperties = new Dictionary<Type, PropertyInfo[]>();
foreach (var item in list)
{
var t = item.GetType();
if (!itemProperties.ContainsKey(t))
{
itemProperties[t] = t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
}
}
return itemProperties.GroupBy(kv => kv.Key, kv=>kv.Value);
}
}
You can also get the same result, by scanning only the first item in the list and assuming the remaining items are of the same time. This time, like in your question, I re-assign the list with a new set of items of a different type.
This produces the following result:
Class1
InterfaceProperty
Class1Property
Class2
InterfaceProperty
Class2Property
from the code:
list = new List<IInterface>();
list.Add(new Class1());
list.Add(new Class1());
list.Add(new Class1());
var item1 = list.First();
var properties1 = item1.GetType().GetProperties();
Console.WriteLine($"{item1.GetType().Name}");
foreach (var prop in properties1)
{
Console.WriteLine($"\t{prop.Name}");
}
list = new List<IInterface>();
list.Add(new Class2());
list.Add(new Class2());
var item2 = list.First();
var properties2 = item2.GetType().GetProperties();
Console.WriteLine($"{item2.GetType().Name}");
foreach (var prop in properties2)
{
Console.WriteLine($"\t{prop.Name}");
}
To get the actual type of the list:
Type listType = this.L.GetType();
To get the types of objects it can contain:
Type elementType = listType.GetGenericArguments().Single();
To get the properties for that type:
var properties = elementType.GetProperties();
As explained in https://learn.microsoft.com/de-de/visualstudio/code-quality/ca2227?view=vs-2019 I've got an object with a read only list like this:
public class MyClass {
public int id { get; set; }
public List<string> stringList { get; } = new List<string>;
}
But how can I initialize MyClass by adding data to stringList?
MyClass test = new MyClass(){
id = 1,
stringList = ???
}
You can use not very obvious syntax with collection initializers:
var x = new MyClass
{
id = 1,
stringList = {"as", "ddsd"} // will ADD "as", "ddsd" to stringList
};
Console.WriteLine(string.Join(", ", x.stringList)); // prints as, ddsd
Bur usual approach to handle readonly properties (until C# 9 is released with init only properties and records) is to pass initialization values in constructor.
You can pass the stringList as a parameter in the constructor and assign the property to the parameter:
public class MyClass {
public int id { get; set; }
public List<string> stringList { get; } = new List<string>();
public MyClass(List<string> stringList) {
this.stringList = stringList;
}
}
I would like to replace an object which is referenced in multiple lists with a new instance of matching interface class.
Here is an example to better understand the problem.
There is an interface called IPosition
There are two classes that implement that interface: RealPosition and AccessiblePosition
In my algorithm I am receiving an array of IPosition list, like this: List<IPosition>[], basically multiple lists
It is very common that the lists reference the same instance of an object. Here is a visualisation:
Now I would like to create a new instance of the AccessiblePosition class and update all references in all lists.
Is there a way to do that easily?
Many thanks in advance!
You can create a container for your data.
public interface IContainer<T>
{
T Data { get; set; }
}
And a List<IContainer<IPosition>>.
Now you can change Data of a container instead of changing item references.
You could just iterate through the lists and compare the items.
public interface IPosition
{
int ID { get; set; }
}
public class RealPosition : IPosition
{
public int ID { get; set; }
}
public class AccessiblePosition : IPosition
{
public int ID { get; set; }
}
void Main()
{
var toReplace = new RealPosition { ID = 1 };
var list1 = new List<IPosition>
{
toReplace,
new RealPosition { ID = 2 },
new RealPosition { ID = 3 },
};
var list2 = new List<IPosition>
{
toReplace,
new RealPosition { ID = 4 },
new RealPosition { ID = 5 },
};
var listOfLists = new List<List<IPosition>>{ list1, list2 };
var replacement = new AccessiblePosition{ ID = 42 };
foreach(var list in listOfLists)
{
//must use for here
for(int i = 0; i < list.Count; ++i)
{
if(list[i] == toReplace)
{
list[i] = replacement;
}
}
}
}
I'm messing around with generics and IEnumerable abit, but i'm kindof stuck.
Here's what i'm trying to do:
I want to have a method that returns any collection type - that implements IEnumerable (?) - (so e.g: List, Stack, Queue, ...)
furthermore, i want to be able to return any collection type, of any datatype.
so i want this method to be able to return a List<string>, as well as a Stack<int>, as well as a List<double>... etc etc.
public IEnumerable<T> returnSomething()
{
Stack<int> stackOfInts = new Stack<int>();
List<string> listOfStrings = new List<string>();
return stackOfInts;
}
this is what i've tried so far. this however doesn't work, i get this error:
Cannot implicitly convert type 'System.Collections.Generic.Stack<int>' to 'System.Collections.Generic.IEnumerable<T>'. An explicit conversion exists (are you missing a cast?)
however, if i replace the IEnumerable<T> in the method signature to IEnumerable<int> , i can return any collection of type int. This however means, that now i can't return the ListOfStrings anymore.
would appreciate any suggestions or ideas :)
You need to add a generic type parameter to your method:
public IEnumerable<T> ReturnSomething<T>()
{
Stack<T> stackOfT = new Stack<T>();
return stackOfT;
}
The type parameter appears after the method name, but before the parameters. It is also possible to have a method with more than one type parameter.
When you call the method you can specify the type:
IEnumerable<int> myInts = ReturnSomething<int>();
The trick is to declare <T> right, if you define generic <T>, then you have to stick to it in your methods, so if you have IEnumerable<T> then elsewhere in your method you must use <T> and not <int> or any other type.
It is only latter when you actually use you generic type you substitute generic <T> for a real type.
See a sample
class Foo<T>
{
public IEnumerable<T> GetList()
{
return new List<T>();
}
public IEnumerable<T> GetStack()
{
return new Stack<T>();
}
}
class Program
{
static void Main(string[] args)
{
Foo<int> foo = new Foo<int>();
IEnumerable<int> list = foo.GetList();
IEnumerable<int> stack = foo.GetStack();
Foo<string> foo1 = new Foo<string>();
IEnumerable<string> list1 = foo1.GetList();
IEnumerable<string> stack1 = foo1.GetStack();
}
}
public IEnumerable<T> returnSomething()
{
Stack<int> stackOfInts = new Stack<int>();
return (IEnumerable<T>) stackOfInts;
}
The type parameter needs to be specified by the caller somewhere.
Either when instantiating a generic class:
public class MyClass<T>
{
public IEnumerable<T> returnSomething()
{
Stack<T> stackOfTs = new Stack<T>();
List<T> listOfTs = new List<T>();
return stackOfTs;
}
}
var v = new MyClass<int>();
foreach(var item in v.returnSomething())
{
}
Or when calling a generic method of a non-generic class:
public class MyClass
{
public IEnumerable<T> returnSomething<T>()
{
Stack<T> stackOfTs = new Stack<T>();
List<T> listOfTs = new List<T>();
return stackOfTs;
}
}
var v = new MyClass();
foreach(var item in v.returnSomething<int>())
{
}
For more help full structure given below ...
my model is
public class Student
{
public int studentId { get; set; }
public string studentName { get; set; }
public string subject { get; set; }
public string studentClass { get; set; }
public int RollNumber { get; set; }
}
IEnumerable return datalist
public static IEnumerable<Student> ReturnSomething()
{
IList<Student> studentList = new List<Student>()
{
new Student()
{studentId = 1, studentName = "Bill", subject = "Science", studentClass = "nine", RollNumber = 01},
new Student()
{studentId = 2, studentName = "Steve", subject = "Arts", studentClass = "ten", RollNumber = 03},
new Student()
{studentId = 3, studentName = "Ram", subject = "Commerce", studentClass = "nine", RollNumber = 05},
new Student()
{studentId = 1, studentName = "Moin", subject = "Science", studentClass = "ten", RollNumber = 06}
};
return studentList;
}
and last one is access code
Student student = new Student();
IEnumerable<Student> studentList = ReturnSomething();
foreach (Student VARIABLE in studentList)
{
student.studentName += VARIABLE.studentName + " "+ "Class= ";
student.studentClass += VARIABLE.studentClass + " ";
}
Console.WriteLine(student.studentName + student.studentClass);
Console.ReadKey();
Yes you can return any type if you change IEnumerable<T> to IEnumerable<dynamic>
like this:
public IEnumerable<dynamic> returnSomething()
{
.....
I am wanting to find out if there is a way to initialize a List<T> where T is an object much like a simple collection gets initialized?
Simple Collection Initializer:
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Object Collection Initilizer:
List<ChildObject> childObjects = new List<ChildObject>
{
new ChildObject(){ Name = "Sylvester", Age=8 },
new ChildObject(){ Name = "Whiskers", Age=2 },
new ChildObject(){ Name = "Sasha", Age=14 }
};
The question is, how and if you can do something like this?
List<ChildObject> childObjects = new List<ChildObject>
{
{ "Sylvester", 8} , {"Whiskers", 2}, {"Sasha", 14}
};
If you look at the docs for collection initializers, it's all about the collection's Add method. Just subclass the closed generic List over your type and make an Add method with the naked parameters. Like
public class MyColl : List<ChildObject>
{
public void Add(string s1, int a1, int a2)
{
base.Add(new ChildObject(s1, a1, a2));
}
}
public class ChildObject
{
public ChildObject(string s1, int a1, int a2)
{
//...
}
}
Then calling it looks like:
static void Main(string[] args)
{
MyColl x = new MyColl
{
{"boo", 2, 4},
{"mang", 3, 5},
};
}
The best you can probably do is something like this:
public class MyListOfChildObjects : List<ChildObject>
{
public void Add( string name, int age )
{
Add ( new ChildObject { Name = name, Age = age } );
}
}
var childObjects = new MyListOfChildObjects
{
{ "Sylvester", 8 } , { "Whiskers", 2 }, { "Sasha", 14 }
};
You could make it more generic, but how would you know which arguments should be bound to each property?
public class MyList<T> : List<T>
{
public void Add( params object[] arguments )
{
// what order should I bind the values to?
}
}
var childObjects = new MyList<ChildObject>
{
{ "Sylvester", 8 } , { "Whiskers", 2 }, { "Sasha", 14 }
};
You can get close by creating your own collection which extends List<ChildObject> and provide your own add method:
public class ChildObjectCollection : List<ChildObject>
{
public void Add(string name, int age)
{
this.Add(new ChildObject(name, age));
}
}
You can then initialise it like this:
var childObjects = new ChildObjectCollection
{
{ "Sylvester", 8} , {"Whiskers", 2}, {"Sasha", 1 }
};
You can't do this without creating your own class derived from List<ChildObject> as per Lee's answer. It's unfortunate that extension methods aren't considered for collection initalizers, otherwise this would work:
// This doesn't work, but it would if collection initializers checked
// extension methods.
using System;
using System.Collections.Generic;
public class ChildObject
{
public string Name { get; set; }
public int Age { get; set; }
}
public static class Extensions
{
public static void Add(this List<ChildObject> children,
string name, int age)
{
children.Add(new ChildObject { Name = name, Age = age });
}
}
class Test
{
static void Main(string[] args)
{
List<ChildObject> children = new List<ChildObject>
{
{ "Sylvester", 8 },
{ "Whiskers", 2 },
{ "Sasha", 14 }
};
}
}
The closest you can get to that is to create a parameterized constructor on your class that accepts those arguments. That won't get you all the way, but you can at least do this:
List<ChildObject> childObjects = new List<ChildObject>
{
new ChildObject("Sylvester", 8) ,
new ChildObject("Whiskers", 2),
new ChildObject("Sasha", 14)
};