在C#中,如何实例化一个方法内传递的genericstypes?
我如何实例化typesT在我的InstantiateType<T>
方法下面?
我得到的错误: “T”是一个“types参数”,但像一个“variables”使用。 :
(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; } } }
温和的答案:
感谢所有的评论,他们让我走上正轨,这就是我想要做的:
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; } } }
声明你的方法是这样的:
public string InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
注意最后的附加约束。 然后在方法体中创build一个new
实例:
T obj = new T();
几个方法。
不指定types必须有一个构造函数:
T obj = default(T); //which will produce null for reference types
用一个构造函数:
T obj = new T();
但是这需要条款:
where T : new()
为了扩展上面的答案,将where T:new()
约束添加到generics方法将需要T有一个公共的,无参数的构造函数。
如果你想避免这种情况 – 而且在工厂模式下,你有时会迫使其他人通过你的工厂方法,而不是直接通过构造函数 – 那么另一种方法是使用reflection( Activator.CreateInstance...
),并保持默认的构造函数私人的。 但是,这当然会带来性能上的损失。
你需要新的 T(),但是你还需要在factory方法的where
规范中添加, new()
有点老,但为其他人寻找解决scheme,也许这可能是有趣的: http : //daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/
两个解决scheme 一个使用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; } }
而不是创build一个函数来实例化types
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 };
使用工厂类来编译lambaexpression式的对象:我发现实例化generics的最快方法。
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(); } }
以下是我设定基准的步骤。
创build我的基准testing方法:
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(); }
为了testing我创build了最简单的类:
public class A { }
要testing的脚本:
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))");
结果超过1 000 000次迭代:
新的A():11ms
FactoryMethod A():275ms
FactoryClass A .Create():56ms
Activator.CreateInstance A():235ms
Activator.CreateInstance(typeof(A)):157ms
备注 :我已经使用.NET Framework 4.5和4.6 (等效结果)进行了testing。
您也可以使用reflection来获取对象的构造函数并实例化:
var c = typeof(T).GetConstructor(); T t = (T)c.Invoke();