사람은 항상 그 사실을 알지 못할 수도 있습니다.Type
컴파일 타임에 객체의 인스턴스를 만들지 만,Type
. 어떻게 새로운 객체 인스턴스를 얻을 수 있습니까?Type
?
그만큼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 = (ObjectType)Activator.CreateInstance(objectType);
그만큼Activator
클래스에는 조금 더 쉽게 만들 수있는 일반적인 변형이 있습니다.
ObjectType instance = Activator.CreateInstance<ObjectType>();
Type t
. - Kevin P. Ricedynamic
어느 것~하다그런 구조를 허용하지만 대부분의 목적을 위해이 대답은 여전히 그것을 다루고있다. - Konrad Rudolph
컴파일 된 표현이 가장 좋습니다! (런타임에 인스턴스를 반복적으로 작성하는 성능).
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
전체 코드 :
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
런타임에? - ajehType
. - NetMage
이 문제의 한 가지 구현은 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 표현또는 몇 가지 간단한IL
opcode 및DynamicMethod
. 어느 쪽이든, 당신은 꽉 루프 또는 여러 통화에 들어가기 시작하면 큰 차이가 있습니다.
리플렉션을 사용하지 않고 :
private T Create<T>() where T : class, new()
{
return new T();
}
기본 생성자를 사용하려면 다음을 사용하는 솔루션을 사용하십시오.System.Activator
아마도 가장 앞선 표현 일 것입니다. 그러나 유형에 기본 생성자가 없거나 기본이 아닌 생성자를 사용해야하는 경우 옵션은 리플렉션 또는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 }
);
제네릭이 아니겠습니까?T t = new T();
작업?
이 문제를 감안할 때 Activator는 매개 변수가없는 ctor가있을 때 작동합니다. 이것이 제약 조건이라면
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
public AbstractType New
{
get
{
return (AbstractType) Activator.CreateInstance(GetType());
}
}
내가이 질문을 건너 뛸 수있는 이유는 임의의 클래스에 대한 간단한 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
비 제너릭 가정에서는 타입에 기본 생성자와 catch가 있습니다. 예외 인 경우는 예외입니다.
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
ObjectType instance
OP의 조건과 일치합니다. "컴파일 타임에 항상 객체의 유형을 알 수는 없습니다." ? :피 - MA-Maddinobject instance = Activator.CreateInstance(...);
. - BrainSlugs83