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; }
}
}
답변 :
모든 의견에 감사드립니다. 그들은 저를 올바른 방향으로 이끌었습니다. 이것이 제가하고 싶은 일입니다.
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()
끝에 추가 제약이 있습니다. 그런 다음 new
메서드 본문에 인스턴스를 만듭니다 .
T obj = new T();
답변
몇 가지 방법.
유형을 지정하지 않으면 생성자가 있어야합니다.
T obj = default(T); //which will produce null for reference types
생성자 사용 :
T obj = new T();
그러나 여기에는 다음 절이 필요합니다.
where T : new()
답변
위의 답변을 확장하려면 where T:new()
제네릭 메서드에 제약 조건을 추가 하려면 T에 매개 변수가없는 공용 생성자가 있어야합니다.
그것을 피하고 싶다면-그리고 팩토리 패턴에서 때때로 다른 사람들이 생성자를 직접 통과하지 않고 팩토리 메서드를 통과하도록 강제하는 경우-대안은 리플렉션 ( Activator.CreateInstance...
) 을 사용 하고 기본 생성자를 비공개로 유지하는 것입니다. 그러나 이것은 물론 성능 저하를 동반합니다.
답변
당신이 원하는 새로운 T를 (),하지만 당신은 추가해야합니다 , new()
받는 where
공장 방법에 대한 사양
답변
조금 오래되었지만 해결책을 찾는 다른 사람들에게는 아마도 이것이 흥미로울 수 있습니다 : http://daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/
두 가지 솔루션. 하나는 Activator를 사용하고 다른 하나는 Compiled Lambda를 사용합니다.
//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;
}
}
답변
리플렉션을 사용하여 개체의 생성자를 가져 와서 인스턴스화 할 수도 있습니다.
var c = typeof(T).GetConstructor();
T t = (T)c.Invoke();
답변
팩토리 클래스를 사용하여 컴파일 된 람바 식으로 개체 빌드 : 제네릭 형식을 인스턴스화하는 가장 빠른 방법입니다.
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))");
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 (동등한 결과)을 사용하여 테스트했습니다 .