Mục đích của Activator.CreateInstance với ví dụ?


124

Ai đó có thể giải thích Activator.CreateInstance()mục đích chi tiết?


6
Có lẽ là tài liệu và ví dụ lớn hơn không có sẵn trong tình trạng quá tải chung. Tôi sẽ khuyến khích rằng tài liệu từ CreateInstance(Type type)phù hợp với CreateInstance<T>()quá tải.
Claus Jørgensen

4
Trang MSDN chỉ có một dòng giải thích duy nhất, "Chứa các phương thức để tạo các loại đối tượng cục bộ hoặc từ xa hoặc có được các tham chiếu đến các đối tượng từ xa hiện có. Lớp này không thể được kế thừa." msdn.microsoft.com/en-us/l
Library / system.activator.aspx

2
Nếu bạn đến đây từ nền Java, đây là c#.netcách làm Object xyz = Class.forName(className).newInstance();.
SNag

Có tài liệu tốt hơn cho nó ở đây .
jpaugh

Câu trả lời:


149

Giả sử bạn có một lớp được gọi MyFancyObjectnhư thế này dưới đây:

class MyFancyObject
{
 public int A { get;set;}
}

Nó cho phép bạn bật:

String ClassName = "MyFancyObject";

Vào

MyFancyObject obj;

Sử dụng

obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))

và sau đó có thể làm những thứ như:

obj.A = 100;

Đó là mục đích của nó. Nó cũng có nhiều tình trạng quá tải khác như cung cấp một Typethay vì tên lớp trong một chuỗi. Tại sao bạn sẽ có một vấn đề như thế là một câu chuyện khác. Đây là một số người cần nó:


2
Điều này tỏ ra hữu ích với tôi. Trong trường hợp của tôi, lớp nằm trong một không gian tên khác, vì vậy tôi phải đảm bảo rằng tôi đã bao gồm không gian tên trong chuỗi ClassName của mình (tức là String ClassName = "My.Namespace.MyFancyObject";).
Scott

1
Bạn đã quên thêm Unwrap (). Bạn cũng có thể đặt null, thay vì "MyAssugging" và hệ thống sẽ tìm kiếm hội hiện tại.
Tony

1
Tôi có thể làm một cái gì đó như thế này obj = (MyFancyObject)Activator.CreateInstance("MyAssembly", ClassName))nhưng thay vì đúc với các loại. Truyền với loại được làm từ ClassName? Như thế này Type type = Type.GetType(ClassName);obj = (type )Activator.CreateInstance("MyAssembly", ClassName))?
rluks

1
Sự khác biệt ở trên khác với: MyFancyObject obj = new MyFancyObject như thế nào?
Ed Landau

1
@Ed Landau Sự khác biệt là bạn có thể khởi tạo một đối tượng trong thời gian chạy mà bạn không biết loại đó vào thời gian biên dịch. Ví dụ: nếu bạn đang xây dựng một hệ thống plugin cho chương trình của mình. Các liên kết trong câu trả lời có thể cung cấp cho bạn một số ý tưởng khi không thể viết MyFancyObject obj = new MyFancyObject (). Điều này thường sẽ được kết hợp với việc sử dụng sự phản chiếu nói chung. Bạn cũng có thể kiểm tra stackoverflow.com/questions/9409293/ cho một mô tả khác.
deepee1

47

Vâng, tôi có thể cho bạn một ví dụ tại sao sử dụng một cái gì đó như thế. Hãy nghĩ về một trò chơi mà bạn muốn lưu trữ cấp độ và kẻ thù của mình trong một tệp XML. Khi bạn phân tích tệp này, bạn có thể có một phần tử như thế này.

<Enemy X="10" Y="100" Type="MyGame.OrcGuard"/>

những gì bạn có thể làm bây giờ là, tạo động các đối tượng được tìm thấy trong tệp cấp của bạn.

foreach(XmlNode node in doc)
   var enemy = Activator.CreateInstance(null, node.Attributes["Type"]);

Điều này rất hữu ích, để xây dựng môi trường năng động. Tất nhiên cũng có thể sử dụng điều này cho các tình huống Plugin hoặc addin và nhiều hơn nữa.


5
Tôi hiểu rằng đó là để tạo ra một thể hiện mới của một loại, nhưng đây là một ví dụ đơn giản tốt đẹp về lý do tại sao một người muốn làm như vậy.
jamiebarrow

14

MSDN, người bạn tốt của tôi có thể giải thích cho bạn, với một ví dụ

Đây là mã trong trường hợp liên kết hoặc nội dung thay đổi trong tương lai:

using System;

class DynamicInstanceList
{
    private static string instanceSpec = "System.EventArgs;System.Random;" +
        "System.Exception;System.Object;System.Version";

    public static void Main()
    {
        string[] instances = instanceSpec.Split(';');
        Array instlist = Array.CreateInstance(typeof(object), instances.Length);
        object item;
        for (int i = 0; i < instances.Length; i++)
        {
            // create the object from the specification string
            Console.WriteLine("Creating instance of: {0}", instances[i]);
            item = Activator.CreateInstance(Type.GetType(instances[i]));
            instlist.SetValue(item, i);
        }
        Console.WriteLine("\nObjects and their default values:\n");
        foreach (object o in instlist)
        {
            Console.WriteLine("Type:     {0}\nValue:    {1}\nHashCode: {2}\n",
                o.GetType().FullName, o.ToString(), o.GetHashCode());
        }
    }
}

// This program will display output similar to the following: 
// 
// Creating instance of: System.EventArgs 
// Creating instance of: System.Random 
// Creating instance of: System.Exception 
// Creating instance of: System.Object 
// Creating instance of: System.Version 
// 
// Objects and their default values: 
// 
// Type:     System.EventArgs 
// Value:    System.EventArgs 
// HashCode: 46104728 
// 
// Type:     System.Random 
// Value:    System.Random 
// HashCode: 12289376 
// 
// Type:     System.Exception 
// Value:    System.Exception: Exception of type 'System.Exception' was thrown. 
// HashCode: 55530882 
// 
// Type:     System.Object 
// Value:    System.Object 
// HashCode: 30015890 
// 
// Type:     System.Version 
// Value:    0.0 
// HashCode: 1048575

1
Không thể xảy ra đối với MSDN và sao chép nội dung ở đây gần như vi phạm bản quyền;)
Claus Jørgensen

13
Bạn đúng. Cá nhân tôi cảm thấy nguyên tắc cũng hoạt động để đưa ra câu trả lời tốt hơn. Tôi thường đến SO với rất nhiều suy nghĩ từ dự án hiện tại của tôi. Tôi thường chỉ muốn một câu trả lời đơn giản và chính xác, vì vậy tôi có thể tiếp tục nơi tôi rời đi. Tôi ghét phải mở các bài báo, đôi khi thậm chí liên kết đến các bài viết khác. Nhiều người trả lời không nhận ra rằng nhiều người không đến đây với thời gian để đọc qua một số bài báo, với vô số lời giới thiệu và nói chuyện không cần thiết. Tóm tắt ngắn gọn những phần quan trọng của một bài viết hay là chìa khóa cho một số câu trả lời hay nhất tôi từng thấy.
Aske B.

10

Bạn cũng có thể làm điều này -

var handle = Activator.CreateInstance("AssemblyName", 
                "Full name of the class including the namespace and class name");
var obj = handle.Unwrap();

Unwrap () là mảnh còn thiếu. :)
Tony

Tôi không thể tìm thấy phương thức 'Unwrap ()' ở trên để sử dụng (như trên). Có điều gì đó đã thay đổi trong các API .NET mới?
Sam

Nó vẫn còn trong không gian tên hệ thống.
William

2
Bạn có thể cung cấp một số giải thích bổ sung về những gì .Unwrap()chính xác và làm thế nào điều này liên quan đến các giải pháp khác?
Jeroen Vannevel

@Sam nó quá tải về CreateInstancenơi nó trở lại System.Runtime.Remoting.ObjectHandle.
nawfal

9

Một ví dụ điển hình có thể là tiếp theo: ví dụ bạn có một bộ Loggers và bạn cho phép người dùng chỉ định loại sẽ được sử dụng trong thời gian chạy thông qua tệp cấu hình.

Sau đó:

string rawLoggerType = configurationService.GetLoggerType();
Type loggerType = Type.GetType(rawLoggerType);
ILogger logger = Activator.CreateInstance(loggerType.GetType()) as ILogger;

HOẶC trường hợp khác là khi bạn có một nhà máy thực thể chung, tạo ra thực thể và cũng chịu trách nhiệm khởi tạo một thực thể bằng dữ liệu nhận được từ DB:

(mã giả)

public TEntity CreateEntityFromDataRow<TEntity>(DataRow row)
 where TEntity : IDbEntity, class
{
   MethodInfo methodInfo = typeof(T).GetMethod("BuildFromDataRow");
   TEntity instance = Activator.CreateInstance(typeof(TEntity)) as TEntity;
   return methodInfo.Invoke(instance, new object[] { row } ) as TEntity;
}

Điều này không hoạt động, typeof(loggerType)kết quả làloggerType is a variable and used like a type
Barkermn01

3

Các Activator.CreateInstancephương pháp tạo ra một thể hiện của một loại quy định sử dụng các nhà xây dựng phù hợp tốt nhất các thông số quy định.

Ví dụ: giả sử bạn có tên loại dưới dạng chuỗi và bạn muốn sử dụng chuỗi để tạo phiên bản của loại đó. Bạn có thể sử dụng Activator.CreateInstancecho việc này:

string objTypeName = "Foo";
Foo foo = (Foo)Activator.CreateInstance(Type.GetType(objTypeName));

Đây là một bài viết MSDN giải thích chi tiết hơn về ứng dụng của nó:

http://msdn.microsoft.com/en-us/l Library / wccyzw83.aspx


5
Hoặc bạn chỉ có thể sử dụng new Foo(). Tôi nghĩ rằng OP muốn một ví dụ thực tế hơn.
Konrad Rudolph

1
Tôi đồng ý với @Konrad. Lý do sử dụng CreateInstancelà nếu bạn không biết loại đối tượng bạn sẽ khởi tạo tại thời điểm thiết kế. Trong ví dụ này, bạn biết rõ loại của nó Foovì bạn đang chọn nó là loại Foo. Bạn sẽ không bao giờ làm điều này bởi vì bạn chỉ có thể làm Foo foo = new Foo().
theyetiman 23/12/13

1

Xây dựng deepee1 và đây , đây là cách chấp nhận tên lớp trong chuỗi, sau đó sử dụng nó để đọc và ghi vào cơ sở dữ liệu với LINQ. Tôi sử dụng "động" thay vì truyền của deepee1 vì nó cho phép tôi gán các thuộc tính, cho phép chúng tôi tự động chọn và vận hành trên bất kỳ bảng nào chúng tôi muốn.

Type tableType = Assembly.GetExecutingAssembly().GetType("NameSpace.TableName");
ITable itable = dbcontext.GetTable(tableType);

//prints contents of the table
foreach (object y in itable) {
    string value = (string)y.GetType().GetProperty("ColumnName").GetValue(y, null);
    Console.WriteLine(value);
}

//inserting into a table
dynamic tableClass = Activator.CreateInstance(tableType);
//Alternative to using tableType, using Tony's tips
dynamic tableClass = Activator.CreateInstance(null, "NameSpace.TableName").Unwrap();
tableClass.Word = userParameter;
itable.InsertOnSubmit(tableClass);
dbcontext.SubmitChanges();

//sql equivalent
dbcontext.ExecuteCommand("INSERT INTO [TableNme]([ColumnName]) VALUES ({0})", userParameter);

0

Tại sao bạn sẽ sử dụng nó nếu bạn đã biết về lớp học và sẽ chọn nó? Tại sao không làm theo cách cũ và làm cho lớp như bạn luôn làm cho nó? Không có lợi thế cho điều này qua cách nó được thực hiện bình thường. Có cách nào để lấy văn bản và vận hành trên đó không:

label1.txt = "Pizza" 
Magic(label1.txt) p = new Magic(lablel1.txt)(arg1, arg2, arg3);
p.method1();
p.method2();

Nếu tôi đã biết Pizza của nó thì không có lợi thế nào:

p = (Pizza)somefancyjunk("Pizza"); over
Pizza p = new Pizza();

nhưng tôi thấy một lợi thế rất lớn cho phương pháp Phép thuật nếu nó tồn tại.


0

Kết hợp với sự phản chiếu, tôi thấy Activator.CreateInstance rất hữu ích trong việc ánh xạ kết quả thủ tục được lưu trữ vào một lớp tùy chỉnh như được mô tả trong câu trả lời sau .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.