Generic function add element to list - c#

I want to replace AddQuickElement and AddRangeElement with one generic function AddElement<T>. But how can i add generic element to List<Base> list. Activator do not work. Or what is better way to make this without reflection?
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
List<Base> list = new List<Base>();
AddQuickElement(list,5);
AddRangeElement(list, 5);
AddElement<Quick>(list,5);
Console.WriteLine(list.Count);
Console.ReadKey();
}
public static void AddQuickElement(List<Base> list, int number)
{
for (int i = 0; i < number; i++)
{
list.Add(new Quick());
}
}
public static void AddRangeElement (List<Base> list, int number)
{
for (int i = 0; i < number; i++)
{
list.Add(new Range());
}
}
public static void AddElement<T>(List<Base> list, int number)
{
Type type = typeof(T);
var element = Activator.CreateInstance(type);
// list.Add(element); // do not work
}
}
public abstract class Base
{
}
public class Quick:Base
{
}
public class Range : Base
{
}
}

You need to constraint the type parameter to AddElement method
public static void AddElement<T>(List<Base> list, int number) where T : Base, new()
{
for (int i = 0; i < number; i++)
{
list.Add(new T());
}
}
The type constraints where T : Base, new() mean that the type T
is derived from Base
has a public parameterless constructor.
(1) lets you add an instance of T to a List<Base>, (2) lets you create a new instance of T using new T().

Related

C# Find Number of elements present in array

I want to create static class which is generic. That class should pass through each property and check if is array. If result is true, than class should check how many elements are present in class and to return that number.
What I had did till now:
public static class Helper<T> where T : class
{
private static int _counter = 0;
public static int Counter()
{
Type type = typeof(T);
foreach (var property in type.GetProperties())
{
if (property.PropertyType.IsArray)
{
}
}
return _counter;
}
}
I need help how to get number of present elements in array.
If you also want to use it on a instanced object instead of an Type you could do s.th. like this (remove the generic type of Helper and make the Counter method generic):
public static class Helper
{
// This method will only iterate the public static properties
public static int Counter<T>() where T : class => Counter(typeof(T), null);
// This method will iterate all public properties
public static int Counter<T>(T objectToCount) where T : class
{
if(objectToCount == null)
{
throw new ArgumentNullException(nameof(objectToCount));
}
return Counter(typeof(T), objectToCount);
}
public static int Counter(Type type, object instance)
{
int _counter = 0;
PropertyInfo[] properties = null;
if(instance == null)
{
properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public);
}
else
{
properties = type.GetProperties();
}
foreach (var property in properties)
{
if (property.PropertyType.IsArray)
{
var array = property.GetValue(instance, null) as Array;
var length = array?.Length;
// do s.th. with your counter
}
}
return _counter;
}
}
then you could use it like:
Helper.Counter(x);
Helper.Counter<TestClass>();
Helper.Counter<TestClass>(x);
Update:
for only instanced objects it could be simplified to this:
public static int Counter(object objectToCount)
{
if(objectToCount == null)
{
throw new ArgumentNullException(nameof(objectToCount));
}
int _counter = 0;
foreach (var property in objectToCount.GetType().GetProperties())
{
if (property.PropertyType.IsArray)
{
var array = property.GetValue(objectToCount, null) as Array;
var length = array?.Length;
// do s.th. with your counter
}
}
return _counter;
}
If I get your question right, you want to get the number of array properties of a class.
in this case, you could choose two approaches.
extention method:
public static class Extensions
{
public static int NumbeofArays<TClass>(this TClass entry) where TClass : class, new()
{
Type type = typeof(TClass);
int arrays = 0;
foreach (var propertyInfo in type.GetProperties())
{
if (propertyInfo.PropertyType.IsArray)
arrays = arrays + 1;
}
return arrays;
}
}
Or a Helper Class:
public static class ClassHelper<TClass> where TClass : class, new()
{
static ClassHelper()
{
Type type = typeof(TClass);
int arrays = 0;
foreach (var propertyInfo in type.GetProperties())
{
if (propertyInfo.PropertyType.IsArray)
arrays = arrays + 1;
}
NumberofArrays = arrays;
}
public static int NumberofArrays { get; }
}
public static int Counter()
{
Type type = typeof(T);
foreach (var property in type.GetProperties())
{
Console.WriteLine(property.Name);
if (property.PropertyType.IsArray)
{
var array = property.GetValue(null, null) as Array;
Console.WriteLine(array.Length);
}
}
return _counter;
}
example: https://dotnetfiddle.net/2ICron

Convert array type to singular

In C# is it possible to convert an array type to singular - for use with Activator.CreateInstance. Take this for example:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
// possibly convert type here? (from array to singular - type[] to type)
Debug.WriteLine($"{type}");
objects.Add(Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}
Gets the following output:
If I understand your Question right you might want something like this using Type.GetElementType() via reflection.
static void Main(string[] args)
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
var typeInstance = type.GetElementType();
if (typeInstance != null)
{
Debug.WriteLine($"{typeInstance}");
objects.Add(Activator.CreateInstance(typeInstance));
}
else
{
objects.Add(Activator.CreateInstance(type));
}
}
}
public class ExampleClass
{
public int X;
public int Y;
}
If I understand your question correctly, you want to get the base-type of an array, right? That should be quite easy with the IsArray property of the type, simply check each entry of your list like this:
private static Type GetTypeOrElementType(Type type)
{
if (!type.IsArray)
return type;
return type.GetElementType();
}
Btw, if you want to create a new Array of that specific type, you can use Array.CreateInstance instead of Activator.CreateInstance
Found this works:
void Main()
{
var types = new[] { typeof(ExampleClass), typeof(ExampleClass[]) };
var objects = new List<object>();
foreach (var type in types)
{
Debug.WriteLine($"{type}");
objects.Add(type.IsArray
? Activator.CreateInstance(type, 1)
: Activator.CreateInstance(type));
}
}
// Define other methods and classes here
public class ExampleClass
{
public int X;
public int Y;
}

C# Working with a generic list in a method

I have been teaching myself generics and I wanted to try it out with a list but I struggled upon a problem I cant figure out how to "feed" the generic list to my method. What is the proper way to make a generic method "eat" my list? :)
Heres my code:
class Program<AnyDataType>
{
static void Main(string[] args)
{
jdtlist.Add("something");
jdtlist.Add("something");
jdtlist.Add("something");
Console.WriteLine(countlist(jdtlist));
Console.ReadKey();
}
static List<AnyDataType> jdtlist = new List<AnyDataType>();
public static int countlist(List<AnyDataType> list) // Yes I know this is practically useless but thats not why I am here :)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
If you are writing generic method, then it should have generic parameter
public static int CountList<T>(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
listcount++;
return listcount;
}
Then you can call it with any generic list
var list = new List<AnyDataType>();
// ..
Foo.CountList(list);
Same goes to classes. If you want to parametrize class with some generic type, you should provide generic argument
public class Foo<T>
As #DStanley stated, you don't need to parametrize individual methods in that case
public class Foo<T>
{
public static int CountList(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
listcount++;
return listcount;
}
}
But you need to parametrize class
Foo<int>.CountList(list)
Suggested reading: Generics (C# Programming Guide)
Your problem is not passing the list to your method - that part is fine. Your problem is that you're trying to fill a "generic" list with a "specific" type (namely strings). Making a class generic means "I am not specifying the data type here - the consumer of the class will do that". So a better use case for your class would be:
class Program
{
static void Main(string[] args)
{
MyList<string>.Add("something");
MyList<string>.Add("something");
MyList<string>.Add("something");
Console.WriteLine(MyList<string>.countlist(MyList<string>.jdtlist));
Console.ReadKey();
}
}
public class MyList<AnyDataType>
{
public static List<AnyDataType> jdtlist = new List<AnyDataType>();
public static void Add(AnyDataType item)
{
jdtList.Add(item);
}
public static int countlist(List<AnyDataType> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
This is the minimum needed to get your program to work - there are several improvements that can be made (not using static so much, etc.) but hopefully it helps you understand generics better.
You need to call the static method of the generic class via class-name including the type of the parameter:
so instead of
Console.WriteLine(countlist(jdtlist));
this:
Console.WriteLine(Program<string>.countlist(jdtlist));
Another way is to make the method generic, not the class:
public static int countlist<AnyDataType>(List<AnyDataType> list) {}
Then you can call it in these ways(with explicit type or inferred from parameter):
Program1.countlist<string>(jdtlist)
Program1.countlist(jdtlist)
Okay you have:
public static int countlist(List<AnyDataType> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
And well, it works fine, but only if you have List<AnyDataType> to begin with.
Well, you could do:
public static int Countlist<T>(List<T> list)
{
int listcount = 0;
for (int i = 0; i < list.Count; i++)
{
listcount++;
}
return listcount;
}
Now the method itself is generic. What's more overloads will happen automatically in that you can call CountList(new List<string>()) rather than having to explicitly call CountList<strong>(new List<string>()).
But this combines with simple matters of inheritance. Consider that your CountList could work just as well with any other IEnumerable<T> implementation:
public static int Count<T>(IEnumerable<T> source)
{
int tally = 0;
foreach(var item in source)
++tally;
return tally;
}
So just as generics mean you don't have to restrict yourself to a particular type of list, so normal inheritance and interface implementation means you can work with the most general case applicable.

Populating a list based on its element type when passed to a method

Not sure if it's possible, but I'd like to be able to populate a List<T> based on what T is. Presently, I have something like this (please forgive the generic names - it's for testing purposes):
public static class CollectionsClass
{
List<Object1> list1 = new List<Object1>();
List<Object2> list2 = new List<Object2>();
List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
if (list.GetType() == typeof(List<Object1>))
{
list.Add(new Object1());
}
else if (list.GetType() == typeof(List<Object2>))
{
list.Add(new Object2());
}
else if (list.GetType() == typeof(List<Object3>))
{
list.Add(new Object3());
}
else
{
// put out an error
}
}
}
}
While that code works, I'd like to shrink it by doing something like:
list.Add(new list.ObjectType());
I've been messing around with reflections and getting types all day, but I just can't seem to figure this one out.
Don't use dynamics, use generics:
static void Populate<T>(List<T> list, ...) where T: new()
{
...
for (int i=0; i<rndNum; i++)
list.Add(new T());
}
Since you're already using dynamic, you should be able to add method to handle this:
private static void AddToList<T>(List<T> list) where T : new()
{
list.Add(new T());
}
Given that, you can write:
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
AddToList(list);
}
}
Try to use generic method:
public static class CollectionsClass
{
public static List<Object1> list1 = new List<Object1>();
public static List<Object2> list2 = new List<Object2>();
public static List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
}
Sounds like you want a combination of generics and reflection.
First of all make it generic:
void Populate<T>(List<T> mylist)
Now you know the type of your list: it's T.
All that is left is looping and creating instances of a particular type T. For this you can use Activator.CreateInstance:
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
With this sample code:
void Main()
{
Populate<Type1>(new List<Type1>());
Populate<Type2>(new List<Type2>());
}
void Populate<T>(List<T> mylist){
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
foreach(var item in mylist){
Console.WriteLine (item);
}
}
class Type1 { }
class Type2 { }
class Type3 { }
You get this output:
This will rely on reflection to create an instance of your object any assumes there is a public non-parameter constructor available (otherwise an exception will be thrown from the Activator).
This is not quite desirable behaviour and I realized it as soon as I saw the other answers that use the where T : new() constraint in their generic function: use this method over mine.
I'll still leave it in here for completeness though (at the very least it demonstrates a possible trap).
Use factory to extract the creation logic, reflection to get the correct type, and Activator to get the instance.
public static class TFactory
{
public static T Getmplementation<T>()
{
var typeName = typeof(T).Name;
var type = Type.GetType(typeName);
if (type != null)
return Activator.CreateInstance(type) as T;
else
throw new NotImplementedException(typeName);
}
}
Then,
List.Add(TFactory.GetImplmentation<'T>());
You can use a generic with a new constraint to achieve this:
private static void PopulateList<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
The constraint is that the type T must provide a default constructor. If you want to add items to a List, you do not need the dynamic keyword as you can specify List<T> as parameter type directly.
If you cannot add a default constructor, you can also provide a creator function:
private static void PopulateList<T>(List<T> list, Func<int, T> creatorFunc,
int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(creatorFunc(i));
}
}
You call the method like this:
var lst = new List<MyObjectType>();
PopulateList<MyObjectType>(lst, x => new MyObjectType(x), 1, 7);
In this sample, the value of i is provided to the creatorFunc that returns a new object of type MyObjectType.

Iterating through fields, which are lists, of an abstract class and passing them to a method of type T?

I have a class that contains a number of lists:
public static class CollectionsClass
{
public static List<Object1> list1 = new List<Object1>();
public static List<Object2> list2 = new List<Object2>();
public static List<Object3> list3 = new List<Object3>();
}
I also have a class that performs actions on those lists:
public static class ActionClass
{
private static Random _rnd = new Random();
public static void PopulateCollections()
{
Populate(list1, 0, 1000);
Populate(list2, 0, 1000);
Populate(list3, 0, 1000);
}
private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
where T: new()
{
int popSize = _rnd.Next(minLimit, maxLimit);
for (int i = 0; i < popSize; i++)
{
list.Add(new T());
}
}
}
Because the number of lists may change, what I would like to do is something like this:
public static void PopulateCollections()
{
var fields = typeof(CollectionsClass).GetFields();
foreach (var field in fields)
{
Populate(field, 0, 1000);
}
}
Unfortunately, that gives me an error:
The type arguments for method 'app.ActionClass.Populate
(System.Collections.Generic.List, int, int)' cannot be inferred
from the usage. Try specifying the type arguments explicitly.
So, there's obviously some problem with it not knowing what
type I'm passing... but I thought that it'd be obvious from field.
You can get the value of a field, for which you have a FieldInfo object, using the GetValue method. Then you need to call the generic method with the correct type parameter. While that can be constructed using reflection, I suggest you try dynamic programming:
public static void PopulateCollections()
{
var fields = typeof(CollectionsClass).GetFields();
foreach (var fieldInfo in fields)
{
dynamic field = fieldInfo.GetValue(null);
Populate(field, 0, 1000);
}
}
The code above assumes that those fields are all static, and that there are no other fields than those of type List<T>.
I've used reflection for that:
public static class CollectionsClass
{
public static List<Object1> list1 = new List<Object1>();
public static List<Object2> list2 = new List<Object2>();
public static List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
public static void PopulateCollections()
{
var fields = typeof(CollectionsClass).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
foreach (var field in fields)
{
var method = typeof(ActionClass).GetMethod("Populate", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).MakeGenericMethod(field.FieldType.GenericTypeArguments[0]);
method.Invoke(null, System.Reflection.BindingFlags.Static, null, new object[] { field.GetValue(null), 0, 1000 }, Thread.CurrentThread.CurrentCulture);
}
}
}

Categories

Resources