Câu trả lời:
Các Activator
lớp trong thư mục gốc System
namespace là khá mạnh mẽ.
Có rất nhiều quá tải để truyền tham số cho hàm tạo và như vậy. Kiểm tra các tài liệu tại:
http://msdn.microsoft.com/en-us/l Library / system.activator.createinstance.aspx
hoặc (đường dẫn mới)
https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance
Dưới đây là một số ví dụ đơn giản:
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
ObjectType instance
phù hợp với điều kiện của OP "Một người có thể không phải lúc nào cũng biết loại đối tượng tại thời điểm biên dịch"? : P
object instance = Activator.CreateInstance(...);
.
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
Các Activator
lớp học có một biến thể chung mà làm cho điều này một chút dễ dàng hơn:
ObjectType instance = Activator.CreateInstance<ObjectType>();
dynamic
cấu trúc mà không cho phép các cấu trúc như vậy nhưng đối với hầu hết các mục đích câu trả lời này vẫn bao gồm nó.
Biểu hiện tổng hợp là cách tốt nhất! (để thực hiện nhiều lần tạo cá thể trong thời gian chạy).
static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
X x = YCreator();
Thống kê (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
Thống kê (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
Thống kê (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
Thống kê (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
Thống kê (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
Thống kê (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
Mã đầy đủ:
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
đang chạy không?
Type
.
Một cách thực hiện của vấn đề này là cố gắng gọi hàm tạo không tham số của Kiểu:
public static object GetNewObject(Type t)
{
try
{
return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return null;
}
}
Đây là cách tiếp cận tương tự, được chứa trong một phương thức chung:
public static T GetNewObject<T>()
{
try
{
return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return default(T);
}
}
Nó khá đơn giản. Giả sử rằng tên lớp của bạn là Car
và không gian tên là Vehicles
, sau đó truyền tham số như Vehicles.Car
trả về đối tượng kiểu Car
. Như thế này, bạn có thể tạo bất kỳ trường hợp nào của bất kỳ lớp nào một cách linh hoạt.
public object GetInstance(string strNamesapace)
{
Type t = Type.GetType(strNamesapace);
return Activator.CreateInstance(t);
}
Nếu Tên đủ điều kiện của bạn (nghĩa là, Vehicles.Car
trong trường hợp này) nằm trong một hội đồng khác, thì Type.GetType
nó sẽ là null. Trong những trường hợp như vậy, bạn có vòng lặp thông qua tất cả các hội đồng và tìm Type
. Cho rằng bạn có thể sử dụng mã dưới đây
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;
}
Và bạn có thể lấy ví dụ bằng cách gọi phương thức trên.
object objClassInstance = GetInstance("Vehicles.Car");
Nếu điều này là cho một cái gì đó sẽ được gọi là rất nhiều trong một ví dụ ứng dụng, thì việc biên dịch và lưu trữ mã động bộ đệm thay vì sử dụng trình kích hoạt hoặc nhanh hơn rất nhiều ConstructorInfo.Invoke()
. Hai tùy chọn dễ dàng để biên dịch động được biên dịch Linq Expressions hoặc một số IL
opcodesDynamicMethod
đơn giản và . Dù bằng cách nào, sự khác biệt là rất lớn khi bạn bắt đầu vào các vòng lặp chặt chẽ hoặc nhiều cuộc gọi.
Sẽ không phải là T t = new T();
công việc chung ?
Nếu bạn muốn sử dụng hàm tạo mặc định thì giải pháp sử dụng System.Activator
được trình bày trước đó có lẽ là thuận tiện nhất. Tuy nhiên, nếu loại thiếu một hàm tạo mặc định hoặc bạn phải sử dụng một hàm không mặc định, thì một tùy chọn là sử dụng sự phản chiếu hoặc System.ComponentModel.TypeDescriptor
. Trong trường hợp phản xạ, chỉ cần biết tên loại (với không gian tên của nó là đủ).
Ví dụ sử dụng sự phản chiếu:
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
);
Ví dụ sử dụng 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[]
chính xác là những gì tôi đến câu hỏi này để tìm, cảm ơn!
Không sử dụng Reflection:
private T Create<T>() where T : class, new()
{
return new T();
}
Do vấn đề này, Activator sẽ hoạt động khi có một ctor không tham số. Nếu đây là một hạn chế xem xét sử dụng
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
public AbstractType New
{
get
{
return (AbstractType) Activator.CreateInstance(GetType());
}
}
Tôi có thể vượt qua câu hỏi này bởi vì tôi đang tìm cách triển khai một phương thức CloneObject đơn giản cho lớp tùy ý (với một hàm tạo mặc định)
Với phương thức chung, bạn có thể yêu cầu kiểu thực hiện 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
Với giả định không chung chung, kiểu này có hàm tạo mặc định và bắt ngoại lệ nếu không.
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