tags:

views:

1537

answers:

4

How can I instantiate the type T inside my InstantiateType<T> method below?

I'm getting the error: 'T' is a 'type parameter' but is used like a 'variable'.:

(SCROLL DOWN FOR REFACTORED ANSWER)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestGeneric33
{
    class Program
    {
        static void Main(string[] args)
        {
            Container container = new Container();
            Console.WriteLine(container.InstantiateType<Customer>("Jim", "Smith"));
            Console.WriteLine(container.InstantiateType<Employee>("Joe", "Thompson"));
            Console.ReadLine();
        }
    }

    public class Container
    {
        public T InstantiateType<T>(string firstName, string lastName) where T : IPerson
        {
            T obj = T();
            obj.FirstName(firstName);
            obj.LastName(lastName);
            return obj;
        }

    }

    public interface IPerson
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }

    public class Customer : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Company { get; set; }
    }

    public class Employee : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int EmployeeNumber { get; set; }
    }
}

REFACTORED ANSWER:

Thanks for all the comments, they got me on the right track, this is what I wanted to do:

using System;

namespace TestGeneric33
{
    class Program
    {
        static void Main(string[] args)
        {
            Container container = new Container();
            Customer customer1 = container.InstantiateType<Customer>("Jim", "Smith");
            Employee employee1 = container.InstantiateType<Employee>("Joe", "Thompson");
            Console.WriteLine(PersonDisplayer.SimpleDisplay(customer1));
            Console.WriteLine(PersonDisplayer.SimpleDisplay(employee1));
            Console.ReadLine();
        }
    }

    public class Container
    {
        public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
        {
            T obj = new T();
            obj.FirstName = firstName;
            obj.LastName = lastName;
            return obj;
        }
    }

    public interface IPerson
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }

    public class PersonDisplayer
    {
        private IPerson _person;

        public PersonDisplayer(IPerson person)
        {
            _person = person;
        }

        public string SimpleDisplay()
        {
            return String.Format("{1}, {0}", _person.FirstName, _person.LastName);
        }

        public static string SimpleDisplay(IPerson person)
        {
            PersonDisplayer personDisplayer = new PersonDisplayer(person);
            return personDisplayer.SimpleDisplay();
        }
    }

    public class Customer : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Company { get; set; }
    }

    public class Employee : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int EmployeeNumber { get; set; }
    }
}
+1  A: 

you want new T(), but you'll also need to add , new() to the where spec for the factory method

Ruben Bartelink
whats with the -1? same answer as Joel, 100% fact, but posted before... wierd...
Ruben Bartelink
Obviously Joel's answer is clearer, but that doesn't make it -1 territory...
Ruben Bartelink
i bumped it back up, I understood it, helped, it seems in general people like posted code better than descriptions here
Edward Tanguay
Thanks, the world makes sense again!
Ruben Bartelink
+8  A: 

Declare your method like this:

public string InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()

Notice the additional constraint at the end. Then create a new instance in the method body:

T obj = new T();
Joel Coehoorn
+4  A: 

Couple of ways.

Without specifying the type must have a constructor:

T obj = default(T); //which will produce null for reference types

With a constructor:

T obj = new T();

But this requires the clause:

where T : new()
annakata
The first one will assign null rather than create an instance for reference types.
Joel Coehoorn
Yep. You need to use reflection to create types without a default constructor, default(T) is null for all reference types.
Dan C.
Yep absolutely, included for completeness really.
annakata
+2  A: 

To extend on the answers above, adding where T:new() constraint to a generic method will require T to have a public, parameterless constructor.

If you want to avoid that - and in a factory pattern you sometimes force the others to go through your factory method and not directly through the constructor - then the alternative is to use reflection (Activator.CreateInstance...) and keep the default constructor private. But this comes with a performance penalty, of course.

Dan C.
May I ask what's the downvote for?
Dan C.
I gave you a compensating +1. Very wierd voting patterns...
Ruben Bartelink
It's not the first time people downvote "all other answers" :)
Dan C.
I'll admit to sometimes scurrilously not upvoting 'competing' answers until the dusgt has settled on a question :D I guess (non-points) karma will sort them out!
Ruben Bartelink