blah blah blah is here! blah blah » Close

up0down
link

Hi
I want to create a class that will get a custom type generic list and will add an value of 0 in a specified element. To be more clear here is an example:

I have the following:
public class Clients
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }
}

I have created a list of type Clients
List<Clients>

After I load the list with some data I would like to have a method that I will be able to pass the list and the ClientId property and this method will add value of 0 to the list and return the new list (with the 0 value). I can do this very easily by using Add method of generics, but what I really want is a method or class I can reuse to pass any list of any custom type T.


Is there anyone who can help me please?

thanks in advance

vulpes
17279

What do you mean by adding a value of 0 to the list? If you have a List<Clients> then you can only add a Clients object to it. Do you perhaps mean to add a new Clients object to the list, which will have a ClientId property of 0 by default?

last answered one year ago

3 answers

link

Here's an example of an object whose constructor requires 3 arguments:

using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
Clients c = new Clients(1, "Barack", "Washington");
List<Clients> list = new List<Clients>();
list.Add(c);
AddNew(list, 2, "David", "London");
foreach(Clients cl in list)
{
Console.WriteLine("{0} {1} {2}", cl.ClientId, cl.ClientName, cl.ClientAddress);
}
Console.ReadKey();
}

static void AddNew<T>(List<T> list, int id, string name, string address)
{
T t = (T)Activator.CreateInstance(typeof(T), id, name, address);
list.Add(t);
}
}

public class Clients
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }

public Clients(int clientId, string clientName, string clientAddress)
{
ClientId = clientId;
ClientName = clientName;
ClientAddress = clientAddress;
}
}

user21
60

Thanks a lot. I really appreciate it.

up0down
link

If my above supposition is correct, here's how you could add an element of type T to a list, assuming only that T has a parameterless constructor. Any properties of type int (or any other fundamental numeric type) will be given a value of 0 as the example shows:

using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
Clients c = new Clients();
c.ClientId = 1;
List<Clients> list = new List<Clients>();
list.Add(c);
AddNew(list);
foreach(Clients cl in list)
{
Console.WriteLine(cl.ClientId); // 1 and 0
}
Console.ReadKey();
}

static void AddNew<T>(List<T> list) where T:new()
{
list.Add(new T());
}
}

public class Clients
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }
}

Notice that since List<T> is a reference type, there's no need for the method to return the new List<T> after an element has been added because it's still the same object and the change will therefore be automatically persisted when the method returns.

user21
60

thanks for your reply. How does it adds 0 if I do not pass 0 but rather I pass 1 (c)?

vulpes
17279

When you create a new object, all bytes which it occupies in heap memory are set to zero. This means that all its numeric fields are set to zero by default. So the ClientId property for the new Clients object has a value of 0. The object that was already added to the list before AddNew() was called retains its ClientId property of 1 which we set explicitly.

user21
60

Is there any other way to add specific values rather than 0?

vulpes
17279

Yes, you can do it using reflection. See my second answer below.

up0down
link

To add a new element to the list with its property initialized to a non-default value, you can use code such as this:

using System;
using System.Collections.Generic;
using System.Reflection;

class Test
{
static void Main()
{
Clients c = new Clients();
c.ClientId = 1;
List<Clients> list = new List<Clients>();
list.Add(c);
AddNew(list, "ClientId", 2);
foreach(Clients cl in list)
{
Console.WriteLine(cl.ClientId); // 1 and 2
}
Console.ReadKey();
}

static void AddNew<T>(List<T> list, string propName, int value) where T:new()
{
T t = new T();
Type tt = t.GetType();
list.Add(t);
PropertyInfo pi = tt.GetProperty(propName);
if (pi != null && pi.PropertyType == typeof(int)) // check property exists and is of type int
{
pi.SetValue(t, value, null);
}
}
}

public class Clients
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }
}

user21
60

great. It works perfectly. One last thing. I need to refactor it in order to reuse it in a lot of places. I'm trying to refactor it and pass the original list as a List<T> parameter but I'm getting the following error: 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'WindowsFormsApplication2.AddNullValue.AddNew<T>(System.Collections.Generic.List<T>, string, int, string, string)' Any idea? thanks

vulpes
17279

The code won't work unless T is a type which has a public parameterless constructor because of the presence of the generic constructor constraint T : new(). If you want to do something similar with a type whose constructor takes 3 arguments, then you need to remove the constructor constraint (unfortunately there aren't any which take arguments) and use Activator.CreateInstance to create the object rather than the constructor. A drawback is that the compiler won't then be able to check that T is a suitable type. However, an advantage is that you won't need to use reflection to set the property unless it's one which isn't initialized by the constructor. See my next answer for an example of all this.

Feedback