122 Stimmen

Wie kann man in C# einen übergebenen generischen Typ innerhalb einer Methode instanziieren?

Wie kann ich den Typ T innerhalb meiner InstantiateType<T> Methode unten?

Ich erhalte die Fehlermeldung: T" ist ein "Typparameter", wird aber wie eine "Variable" verwendet. :

(FÜR DIE ÜBERARBEITETE ANTWORT NACH UNTEN SCROLLEN)

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; }
    }
}

ÜBERARBEITETE ANTWORT:

Danke für alle Kommentare, sie haben mich auf den richtigen Weg gebracht, das ist es, was ich tun wollte:

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; }
    }
}

167voto

Joel Coehoorn Punkte 377088

Deklarieren Sie Ihre Methode wie folgt:

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

Beachten Sie die zusätzliche Bedingung am Ende. Erstellen Sie dann eine new Instanz im Körper der Methode:

T obj = new T();

34voto

annakata Punkte 72408

Es gibt zwei Möglichkeiten.

Ohne Angabe des Typs muss ein Konstruktor vorhanden sein:

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

Mit einem Konstruktor:

T obj = new T();

Dazu ist jedoch die Klausel erforderlich:

where T : new()

15voto

Dan C. Punkte 3458

Um die obigen Antworten zu erweitern, sollte man Folgendes hinzufügen where T:new() Einschränkung auf eine generische Methode erfordert, dass T einen öffentlichen, parameterlosen Konstruktor hat.

Wenn Sie das vermeiden wollen - und in einem Fabrikmuster zwingen Sie die anderen manchmal, durch Ihre Fabrikmethode und nicht direkt durch den Konstruktor zu gehen -, dann ist die Alternative, Reflexion zu verwenden ( Activator.CreateInstance... ) und den Standardkonstruktor privat halten. Aber das geht natürlich zu Lasten der Leistung.

8voto

Ruben Bartelink Punkte 57310

Sie wollen nuevo T(), aber Sie müssen auch Folgendes hinzufügen , new() zum where Spezifikation für die Fabrikmethode

6voto

Daniel Punkte 7783

Ein bisschen alt, aber für andere, die nach einer Lösung suchen, könnte das vielleicht von Interesse sein: http://daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/

Zwei Lösungen. Eine mit Activator und eine mit kompilierten Lambdas.

//Person has private ctor
var person = Factory<Person>.Create(p => p.Name = "Daniel");

public static class Factory<T> where T : class 
{
    private static readonly Func<T> FactoryFn;

    static Factory()
    {
        //FactoryFn = CreateUsingActivator();

        FactoryFn = CreateUsingLambdas();
    }

    private static Func<T> CreateUsingActivator()
    {
        var type = typeof(T);

        Func<T> f = () => Activator.CreateInstance(type, true) as T;

        return f;
    }

    private static Func<T> CreateUsingLambdas()
    {
        var type = typeof(T);

        var ctor = type.GetConstructor(
            BindingFlags.Instance | BindingFlags.CreateInstance |
            BindingFlags.NonPublic,
            null, new Type[] { }, null);

        var ctorExpression = Expression.New(ctor);
        return Expression.Lambda<Func<T>>(ctorExpression).Compile();
    }

    public static T Create(Action<T> init)
    {
        var instance = FactoryFn();

        init(instance);

        return instance;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X