在C#中,如何在方法中实例化传递的泛型类型?

Edw*_*uay 90 c# generics

如何在我的InstantiateType<T>方法中实例化类型T ?

我收到错误:'T'是'类型参数'但是像'变量'一样使用.:

(对于经过改进的答案,请向下滚动)

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

改进的答案:

感谢所有评论,他们让我走上正轨,这就是我想要做的:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

Joe*_*orn 113

像这样声明你的方法:

public string InstantiateType<T>(string firstName, string lastName) 
              where T : IPerson, new()
Run Code Online (Sandbox Code Playgroud)

注意最后的附加约束.然后new在方法体中创建一个实例:

T obj = new T();    
Run Code Online (Sandbox Code Playgroud)

  • 多年来我一直在编写C#,在我的日子里有一些繁重的泛型类型滥用,我从来不知道你可以定义这样的约束来实例化泛型类型.非常感谢! (4认同)

ann*_*ata 28

几种方式.

没有指定类型必须有一个构造函数:

T obj = default(T); //which will produce null for reference types
Run Code Online (Sandbox Code Playgroud)

使用构造函数:

T obj = new T();
Run Code Online (Sandbox Code Playgroud)

但这要求条款:

where T : new()
Run Code Online (Sandbox Code Playgroud)


Dan*_* C. 13

为了扩展上面的答案,向where T:new()泛型方法添加约束将要求T具有公共的无参数构造函数.

如果你想避免这种情况 - 并且在工厂模式中你有时强迫其他人通过你的工厂方法而不是直接通过构造函数 - 那么替代方法是使用reflection(Activator.CreateInstance...)并保持默认构造函数为private.但这当然会带来性能损失.


Rub*_*ink 8

你想要新的 T(),但你还需要添加工厂方法, new()where规范


Dan*_*iel 5

有点旧但对于其他寻求解决方案的人来说,也许这可能会引起兴趣:http : //daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/

两种解决方案。一种使用 Activator,一种使用 Compiled 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;
    }
}
Run Code Online (Sandbox Code Playgroud)