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

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

我得到了错误: ‘ T’是一个‘ type 参数’,但是被用作‘ variable’。:

(向下滚动查看重构答案)

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:

感谢所有的评论,他们让我走上了正确的道路,这就是我想做的:

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; }
}
}
69366 次浏览

您需要 newT () ,但是还需要将 , new()添加到工厂方法的 where规范中

这样声明你的方法:

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();

有几个办法。

Without specifying the type must have a constructor:

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

使用构造函数:

T obj = new T();

但这需要一个条款:

where T : new()

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.

有点老旧,但对于其他寻找解决方案的人来说,这可能是令人感兴趣的: http://daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/

Two solutions. One using Activator and one using 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;
}
}

而不是创建一个函数来实例化类型

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

你本可以这么做的

T obj = new T { FirstName = firstName, LastName = lastname };

You can also use reflection to fetch the object's constructor and instantiate that way:

var c = typeof(T).GetConstructor();
T t = (T)c.Invoke();

使用工厂类使用已编译的 lamba 表达式构建对象: 这是我发现的实例化泛型类型的最快方法。

public static class FactoryContructor<T>
{
private static readonly Func<T> New =
Expression.Lambda<Func<T>>(Expression.New(typeof (T))).Compile();


public static T Create()
{
return New();
}
}

下面是我设置基准的步骤。

创建我的基准测试方法:

static void Benchmark(Action action, int iterationCount, string text)
{
GC.Collect();
var sw = new Stopwatch();
action(); // Execute once before


sw.Start();
for (var i = 0; i <= iterationCount; i++)
{
action();
}


sw.Stop();
System.Console.WriteLine(text + ", Elapsed: {0}ms", sw.ElapsedMilliseconds);
}

我还尝试过使用工厂方法:

public static T FactoryMethod<T>() where T : new()
{
return new T();
}

对于测试,我创建了最简单的类:

public class A { }

要测试的脚本:

const int iterations = 1000000;
Benchmark(() => new A(), iterations, "new A()");
Benchmark(() => FactoryMethod<A>(), iterations, "FactoryMethod<A>()");
Benchmark(() => FactoryClass<A>.Create(), iterations, "FactoryClass<A>.Create()");
Benchmark(() => Activator.CreateInstance<A>(), iterations, "Activator.CreateInstance<A>()");
Benchmark(() => Activator.CreateInstance(typeof (A)), iterations, "Activator.CreateInstance(typeof (A))");

超过100万次迭代的结果:

新 A () : 11分

FactoryMethod A () : 275ms

FactoryClass A. Create () : 56ms

Activator.CreateInstance A (): 235ms

Activator.CreateInstance(typeof (A)): 157ms

Remarks: I've tested using both .NET Framework 4.5和4.6 (equivalent results).