Reputation: 4474
I have a function as below.
private IList<ContactList> getEmptyRow()
{
var _ContactList = new List<ContactList>();
_ContactList.Add(new ContactList()
{
Email = string.Empty,
Name = string.Empty
});
return _ContactList;
}
I would like to change my class ContactList
to
private IList<T> getEmptyRow() { ..... T.Add(new T()....
Is this possible ? and how ?
Every suggestion will be appreciated.
Upvotes: 4
Views: 1153
Reputation: 23208
A bit late since you already accepted an answer, but as an alternative, especially if new()
isn't an option, you can setup a provider with pre-defined constructor/initialization syntax which should give you some flexibility:
public static class EmptyRowProvider
{
private static Dictionary<Type, object> TypeCreators = new Dictionary<Type, object>();
public static void RegisterType<T>(Func<T> emptyTypeCreator)
{
TypeCreators.Add(typeof(T), emptyTypeCreator);
}
public static IList<T> GetEmptyRow<T>()
{
object typeCreatorUntyped;
if (!TypeCreators.TryGetValue(typeof(T), out typeCreatorUntyped))
throw new Exception("Type " + typeof(T).FullName + " not registered!");
Func<T> typeCreator = (Func<T>)typeCreatorUntyped;
IList<T> emptyRow = new List<T>();
emptyRow.Add(typeCreator());
return emptyRow;
}
}
Somewhere during your application initialization you would register the type and their factory method. Later on, you just make a call by that type which would run that method:
EmptyRowProvider.RegisterType(() => new ContactList() { Email = String.Empty, Name = String.Empty });
var emptyRow = EmptyRowProvider.GetEmptyRow<ContactList>();
Console.WriteLine(emptyRow.Count); //1
Console.WriteLine(emptyRow[0].Email == String.Empty); //true
Console.WriteLine(emptyRow[0].Name == String.Empty); //true
Say if you had a type that you didn't have a parameterless constructor for, or if later on you decided to change the way it's initialized. Say later you have ContactList
use a different constructor:
public ContactList(string email, string name, bool isPrivate)
{
//initialize data here
}
Then your new code usage might look like:
EmptyRowProvider.RegisterType(() => new ContactList(String.Empty, String.Empty, true));
var emptyRow = EmptyRowProvider.GetEmptyRow<ContactList>();
Console.WriteLine(emptyRow.Count); //1
Console.WriteLine(emptyRow[0].Email == String.Empty); //true
Console.WriteLine(emptyRow[0].Name == String.Empty); //true
Console.WriteLine(emptyRow[0].IsPrivate == true); //true
Or say you push the ContactList
creation to a specific factory method:
EmptyRowProvider.RegisterType(() => ContactListFactory.Create(String.Empty, String.Empty));
And finally, you can register multiple different types with different initializations, but achieve the same usage:
EmptyRowProvider.RegisterType(() => new ContactList(String.Empty, String.Empty, true));
EmptyRowProvider.RegisterType(() => new Person("John", "Doe"));
EmptyRowProvider.RegisterType(() => UserProvider.SetupAnonymousUser("myusername", "mypassword", LoginType.Anonymous));
ContactList emptyContactList = EmptyRowProvider.GetEmptyRow<ContactList>();
Person emptyPerson = EmptyRowProvider.GetEmptyRow<Person>();
User emptyUser = EmptyRowProvider.GetEmptyRow<User>();
Upvotes: 4
Reputation: 161002
Something like this perhaps?
public interface IPerson
{
string Email {get;set;}
string Name {get;set;}
}
public class SomeClass
{
private IList<T> getEmptyRow<T>() where T : IPerson, new()
{
var t = new List<T>();
t.Add(new T()
{
Email = string.Empty,
Name = string.Empty
});
return t;
}
}
You need an interface or base class so you can set the public properties Email
and Name
and you need the new()
constraint so you can use the default constructor.
Upvotes: 6