BaseFruit
을 허용하는 생성자가있는 경우 int weight
이와 같은 일반적인 방법으로 과일 조각을 인스턴스화 할 수 있습니까?
public void AddFruit<T>()where T: BaseFruit{
BaseFruit fruit = new T(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
주석 뒤에 예제가 추가됩니다. BaseFruit
매개 변수가없는 생성자를 제공 한 다음 멤버 변수를 통해 모든 것을 채우는 경우에만이 작업을 수행 할 수 있습니다 . 내 실제 코드 (과일에 관한 것이 아님)에서 이것은 오히려 비실용적입니다.
-Update-
그래서 어떤 식 으로든 제약으로 해결할 수없는 것 같습니다. 답변에서 세 가지 후보 솔루션이 있습니다.
- 공장 패턴
- 반사
- 활성제
나는 반사가 가장 깨끗하지 않다고 생각하는 경향이 있지만 다른 두 가지를 결정할 수는 없습니다.
답변
또한 더 간단한 예 :
return (T)Activator.CreateInstance(typeof(T), new object[] { weight });
T에서 new () 제약 조건을 사용하는 것은 컴파일 타임에 컴파일러가 공용 매개 변수없는 생성자를 확인하도록하기위한 것이므로 형식을 만드는 데 사용되는 실제 코드는 Activator 클래스입니다.
존재하는 특정 생성자에 대해 스스로를 확인해야하며 이러한 종류의 요구 사항은 코드 냄새 일 수 있습니다 (또는 오히려 C #의 현재 버전에서는 피해야 할 것).
답변
매개 변수화 된 생성자를 사용할 수 없습니다. ” where T : new()
“제약 조건 이있는 경우 매개 변수가없는 생성자를 사용할 수 있습니다 .
고통이지만 그런 삶입니다 🙁
이것이 내가 “정적 인터페이스” 로 해결하고 싶은 것 중 하나입니다 . 그런 다음 정적 메소드, 연산자 및 생성자를 포함하도록 T를 제한 한 다음 호출 할 수 있습니다.
답변
예; 위치를 변경하십시오.
where T:BaseFruit, new()
그러나 이것은 매개 변수가없는 생성자 에서만 작동합니다 . 속성을 설정하는 다른 방법이 있어야합니다 (속성 자체 또는 유사한 설정).
답변
가장 간단한 솔루션
Activator.CreateInstance<T>()
답변
Jon이 지적했듯이 이것은 매개 변수가없는 생성자를 제한하는 삶입니다. 그러나 다른 해결책은 팩토리 패턴을 사용하는 것입니다. 이것은 쉽게 구속 할 수 있습니다
interface IFruitFactory<T> where T : BaseFruit {
T Create(int weight);
}
public void AddFruit<T>( IFruitFactory<T> factory ) where T: BaseFruit {
BaseFruit fruit = factory.Create(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
또 다른 옵션은 기능적 접근 방식을 사용하는 것입니다. 팩토리 방식으로 전달하십시오.
public void AddFruit<T>(Func<int,T> factoryDel) where T : BaseFruit {
BaseFruit fruit = factoryDel(weight); /* new Apple(150); */
fruit.Enlist(fruitManager);
}
답변
리플렉션을 사용하여 수행 할 수 있습니다.
public void AddFruit<T>()where T: BaseFruit
{
ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
if (constructor == null)
{
throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
}
BaseFruit fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
fruit.Enlist(fruitManager);
}
편집 : 생성자 == null 검사가 추가되었습니다.
편집 : 캐시를 사용하는 더 빠른 변형 :
public void AddFruit<T>()where T: BaseFruit
{
var constructor = FruitCompany<T>.constructor;
if (constructor == null)
{
throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
}
var fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
fruit.Enlist(fruitManager);
}
private static class FruitCompany<T>
{
public static readonly ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
}
답변
user1471935의 제안에 추가하여 :
하나 이상의 매개 변수가있는 생성자를 사용하여 일반 클래스를 인스턴스화하려면 Activator 클래스를 사용할 수 있습니다.
T instance = Activator.CreateInstance(typeof(T), new object[] {...})
개체 목록은 제공하려는 매개 변수입니다. Microsoft에 따르면 :
CreateInstance […]는 지정된 매개 변수와 가장 일치하는 생성자를 사용하여 지정된 유형의 인스턴스를 작성합니다.
CreateInstance ( CreateInstance<T>()
) 의 일반 버전도 있지만 생성자 매개 변수를 제공 할 수 없습니다.