답변:
Activator
루트 내에서 클래스 System
네임 스페이스는 꽤 강력하다.
매개 변수를 생성자 등에 전달하기위한 과부하가 많이 있습니다. 다음에서 설명서를 확인하십시오.
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
또는 (새로운 경로)
https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance
다음은 간단한 예입니다.
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
ObjectType instance
OP의 조건 "컴파일 타임에 객체의 유형을 항상 알 수있는 것은 아닙니다"와 어떻게 일치합니까? : P
object instance = Activator.CreateInstance(...);
.
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
이 Activator
클래스에는 이것을 좀 더 쉽게 만드는 일반적인 변형이 있습니다.
ObjectType instance = Activator.CreateInstance<ObjectType>();
dynamic
구조 않는 등 구조 그러나 대부분의 목적이 대답은 여전히 그것을 커버를 할 수 있습니다.
컴파일 된 표현이 가장 좋습니다! (런타임에서 반복적으로 인스턴스를 작성하는 성능을 위해).
static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
X x = YCreator();
통계 (2012) :
Iterations: 5000000
00:00:00.8481762, Activator.CreateInstance(string, string)
00:00:00.8416930, Activator.CreateInstance(type)
00:00:06.6236752, ConstructorInfo.Invoke
00:00:00.1776255, Compiled expression
00:00:00.0462197, new
통계 (2015, .net 4.5, x64) :
Iterations: 5000000
00:00:00.2659981, Activator.CreateInstance(string, string)
00:00:00.2603770, Activator.CreateInstance(type)
00:00:00.7478936, ConstructorInfo.Invoke
00:00:00.0700757, Compiled expression
00:00:00.0286710, new
통계 (2015, .net 4.5, x86) :
Iterations: 5000000
00:00:00.3541501, Activator.CreateInstance(string, string)
00:00:00.3686861, Activator.CreateInstance(type)
00:00:00.9492354, ConstructorInfo.Invoke
00:00:00.0719072, Compiled expression
00:00:00.0229387, new
통계 (2017, LINQPad 5.22.02 / x64 / .NET 4.6) :
Iterations: 5000000
No args
00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.3500748, Activator.CreateInstance(Type type)
00:00:01.0100714, ConstructorInfo.Invoke
00:00:00.1375767, Compiled expression
00:00:00.1337920, Compiled expression (type)
00:00:00.0593664, new
Single arg
00:00:03.9300630, Activator.CreateInstance(Type type)
00:00:01.3881770, ConstructorInfo.Invoke
00:00:00.1425534, Compiled expression
00:00:00.0717409, new
통계 (2019, x64 / .NET 4.8) :
Iterations: 5000000
No args
00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.3122015, Activator.CreateInstance(Type type)
00:00:00.8035712, ConstructorInfo.Invoke
00:00:00.0692854, Compiled expression
00:00:00.0662223, Compiled expression (type)
00:00:00.0337862, new
Single arg
00:00:03.8081959, Activator.CreateInstance(Type type)
00:00:01.2507642, ConstructorInfo.Invoke
00:00:00.0671756, Compiled expression
00:00:00.0301489, new
통계 (2019, x64 / .NET Core 3.0) :
Iterations: 5000000
No args
00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.2786803, Activator.CreateInstance(Type type)
00:00:00.6183554, ConstructorInfo.Invoke
00:00:00.0483217, Compiled expression
00:00:00.0485119, Compiled expression (type)
00:00:00.0434534, new
Single arg
00:00:03.4389401, Activator.CreateInstance(Type type)
00:00:01.0803609, ConstructorInfo.Invoke
00:00:00.0554756, Compiled expression
00:00:00.0462232, new
전체 코드 :
static X CreateY_New()
{
return new Y();
}
static X CreateY_New_Arg(int z)
{
return new Y(z);
}
static X CreateY_CreateInstance()
{
return (X)Activator.CreateInstance(typeof(Y));
}
static X CreateY_CreateInstance_String()
{
return (X)Activator.CreateInstance("Program", "Y").Unwrap();
}
static X CreateY_CreateInstance_Arg(int z)
{
return (X)Activator.CreateInstance(typeof(Y), new object[] { z, });
}
private static readonly System.Reflection.ConstructorInfo YConstructor =
typeof(Y).GetConstructor(Type.EmptyTypes);
private static readonly object[] Empty = new object[] { };
static X CreateY_Invoke()
{
return (X)YConstructor.Invoke(Empty);
}
private static readonly System.Reflection.ConstructorInfo YConstructor_Arg =
typeof(Y).GetConstructor(new[] { typeof(int), });
static X CreateY_Invoke_Arg(int z)
{
return (X)YConstructor_Arg.Invoke(new object[] { z, });
}
private static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
return YCreator();
}
private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
Expression.New(typeof(Y))
).Compile();
static X CreateY_CompiledExpression_Type()
{
return YCreator_Type();
}
private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
private static readonly Func<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
YCreator_Arg_Param
).Compile();
static X CreateY_CompiledExpression_Arg(int z)
{
return YCreator_Arg(z);
}
static void Main(string[] args)
{
const int iterations = 5000000;
Console.WriteLine("Iterations: {0}", iterations);
Console.WriteLine("No args");
foreach (var creatorInfo in new[]
{
new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func<X>)CreateY_CreateInstance},
new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
new {Name = "new", Creator = (Func<X>)CreateY_New},
})
{
var creator = creatorInfo.Creator;
var sum = 0;
for (var i = 0; i < 1000; i++)
sum += creator().Z;
var stopwatch = new Stopwatch();
stopwatch.Start();
for (var i = 0; i < iterations; ++i)
{
var x = creator();
sum += x.Z;
}
stopwatch.Stop();
Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
}
Console.WriteLine("Single arg");
foreach (var creatorInfo in new[]
{
new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<int, X>)CreateY_CreateInstance_Arg},
new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
new {Name = "new", Creator = (Func<int, X>)CreateY_New_Arg},
})
{
var creator = creatorInfo.Creator;
var sum = 0;
for (var i = 0; i < 1000; i++)
sum += creator(i).Z;
var stopwatch = new Stopwatch();
stopwatch.Start();
for (var i = 0; i < iterations; ++i)
{
var x = creator(i);
sum += x.Z;
}
stopwatch.Stop();
Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
}
}
public class X
{
public X() { }
public X(int z) { this.Z = z; }
public int Z;
}
public class Y : X
{
public Y() {}
public Y(int z) : base(z) {}
}
X
런타임에 어떤 유형인지 모르는 경우에도 여전히 유용 합니까?
Type
.
이 문제의 한 가지 구현은 Type의 매개 변수없는 생성자를 호출하는 것입니다.
public static object GetNewObject(Type t)
{
try
{
return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return null;
}
}
다음은 일반적인 방법에 포함 된 동일한 접근 방식입니다.
public static T GetNewObject<T>()
{
try
{
return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return default(T);
}
}
꽤 간단합니다. 당신의 클래스 명이라고 가정 Car
및 네임 스페이스가되어 Vehicles
, 다음과 같이 매개 변수를 전달할 Vehicles.Car
반환 타입의 객체 어느 Car
. 이와 같이 모든 클래스의 인스턴스를 동적으로 만들 수 있습니다.
public object GetInstance(string strNamesapace)
{
Type t = Type.GetType(strNamesapace);
return Activator.CreateInstance(t);
}
귀하의 경우 정규화 된 이름 (즉, Vehicles.Car
이 경우) 조립 서로에의는 Type.GetType
null가됩니다. 이러한 경우 모든 어셈블리를 반복하고를 찾습니다 Type
. 이를 위해 아래 코드를 사용할 수 있습니다
public object GetInstance(string strFullyQualifiedName)
{
Type type = Type.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
}
return null;
}
그리고 위의 메소드를 호출하여 인스턴스를 얻을 수 있습니다.
object objClassInstance = GetInstance("Vehicles.Car");
이것이 응용 프로그램 인스턴스에서 많이 호출되는 것이라면 활성제 또는를 사용하는 대신 동적 코드를 컴파일하고 캐시하는 것이 훨씬 빠릅니다 ConstructorInfo.Invoke()
. 동적 컴파일을위한 두 가지 쉬운 옵션은 Linq Expressions 또는 일부 간단한 IL
opcode 및DynamicMethod
입니다. 어느 쪽이든 타이트한 루프 나 여러 호출을 시작할 때 차이가 큽니다.
일반적인 T t = new T();
일이 아닙니까?
기본 생성자를 사용하려면 System.Activator
앞에서 제시 한 솔루션 이 가장 편리합니다. 그러나 유형에 기본 생성자가 없거나 기본이 아닌 유형을 사용해야하는 경우 reflection 또는을 사용하는 옵션이 있습니다 System.ComponentModel.TypeDescriptor
. 리플렉션의 경우 형식 이름 만 있으면 충분합니다 (네임 스페이스 포함).
리플렉션 사용 예 :
ObjectType instance =
(ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
typeName: objectType.FulName, // string including namespace of the type
ignoreCase: false,
bindingAttr: BindingFlags.Default,
binder: null, // use default binder
args: new object[] { args, to, constructor },
culture: null, // use CultureInfo from current thread
activationAttributes: null
);
사용 예 TypeDescriptor
:
ObjectType instance =
(ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
provider: null, // use standard type description provider, which uses reflection
objectType: objectType,
argTypes: new Type[] { types, of, args },
args: new object[] { args, to, constructor }
);
args[]
내가이 질문에 와서 정확히 찾은 것입니다. 감사합니다!
리플렉션을 사용하지 않고 :
private T Create<T>() where T : class, new()
{
return new T();
}
이 문제가 발생하면 매개 변수가없는 ctor가있을 때 Activator가 작동합니다. 이것이 제약 조건이라면
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
임의의 클래스 (기본 생성자와 함께)에 대한 간단한 CloneObject 메소드를 구현하려고했기 때문에이 질문을 가로 챌 수 있습니다.
제네릭 메서드를 사용하면 형식이 New ()를 구현하도록 요구할 수 있습니다.
Public Function CloneObject(Of T As New)(ByVal src As T) As T
Dim result As T = Nothing
Dim cloneable = TryCast(src, ICloneable)
If cloneable IsNot Nothing Then
result = cloneable.Clone()
Else
result = New T
CopySimpleProperties(src, result, Nothing, "clone")
End If
Return result
End Function
제네릭이 아닌 경우 형식에 기본 생성자가 있다고 가정하고 그렇지 않은 경우 예외를 잡습니다.
Public Function CloneObject(ByVal src As Object) As Object
Dim result As Object = Nothing
Dim cloneable As ICloneable
Try
cloneable = TryCast(src, ICloneable)
If cloneable IsNot Nothing Then
result = cloneable.Clone()
Else
result = Activator.CreateInstance(src.GetType())
CopySimpleProperties(src, result, Nothing, "clone")
End If
Catch ex As Exception
Trace.WriteLine("!!! CloneObject(): " & ex.Message)
End Try
Return result
End Function