สร้างตัวอย่างของคลาสจากสตริง


218

มีวิธีการสร้างอินสแตนซ์ของคลาสตามข้อเท็จจริงที่ฉันรู้ชื่อของคลาสที่รันไทม์หรือไม่ โดยทั่วไปฉันจะมีชื่อของชั้นในสตริง


ดูเหมือนว่าคุณจะได้อธิบายถึงวิธีการแก้ปัญหาที่คุณต้องการใช้ แต่ไม่ใช่ปัญหาที่คุณพยายามแก้ไข บางทีคุณกำลังพยายามทำบางสิ่งด้วยความสามารถในการขยายซึ่งในกรณีนี้ฉันขอแนะนำให้คุณตรวจสอบกรอบการจัดการที่ขยายได้
Jay Bazuzi

คำตอบ:


159

ดูที่วิธีการActivator.CreateInstance


15
เกี่ยวข้องกับตัวอย่างที่ยอดเยี่ยม: stackoverflow.com/questions/493490/…
John S.

นอกจากนี้โพสต์นี้จะเกี่ยวข้องเช่นกันตามประเภทของคุณที่จะต้องพบ: stackoverflow.com/questions/1825147/ …
สวนสาธารณะแบรด


4
ตัวอย่างเช่น:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
จบ Tjahjono

2
หมายเหตุสำคัญที่นี่:. แกะ () เพื่อผ่านตัวจัดการการควบคุมระยะไกลเพื่อให้คุณสามารถใช้งานจริงได้ @Endy - ขอบคุณ
Roger Willcocks

77

มันค่อนข้างง่าย สมมติว่า ClassName ของคุณCarและ namespace จะVehiclesแล้วผ่านพารามิเตอร์ซึ่งผลตอบแทนวัตถุประเภทVehicles.Car Carเช่นนี้คุณสามารถสร้างตัวอย่างของคลาสใดก็ได้แบบไดนามิก

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

หากชื่อที่ผ่านการรับรองของคุณ(เช่นVehicles.Carในกรณีนี้) อยู่ในการชุมนุมอื่นType.GetTypeจะเป็นโมฆะ 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;
 }

ตอนนี้ถ้าคุณต้องการเรียกตัวสร้างพารามิเตอร์ทำต่อไปนี้

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

แทน

Activator.CreateInstance(t);

วิธีการใช้งานโดยไม่ต้องร่ายและวิธีการร่ายจากสายอักขระที่กำหนด ?
TaW

1
@TaW - เพื่อที่จะใช้อินสแตนซ์ของคลาสคุณจะต้องมีความรู้เกี่ยวกับสิ่งที่มันจะทำ - ไม่เช่นนั้นคุณจะไม่สามารถใช้มันได้ กรณีการใช้งานที่พบบ่อยที่สุดสำหรับกรณีนี้จะมีการส่งไปยังอินเทอร์เฟซบางตัวซึ่งให้สัญญาที่กำหนดไว้ล่วงหน้า (สิ่งนี้จะระงับหากคุณไม่ใช้dynamicรหัส - ดูstackoverflow.com/a/2690661/904521 )
Tomer Cagan

1
อย่าเข้ารหัสประเภทของตัวแปรในนั้นชื่อเช่น:. มีความจำเป็นต้องใช้คำนำหน้าไม่มีstrFullyQualifiedNameด้วยstr, fullyQualifiedNameจะทำงาน
Mehdi Dehghani

คีย์เวิร์ดstrถูกใช้เป็นส่วนหนึ่งของหลักการตั้งชื่อสำหรับตัวแปร องค์กรและโครงการบางแห่งยืนยันที่จะทำตามสิ่งนี้ดังนั้นฉันจึงใช้ หากคุณจะทำงานใน oraganisation / โครงการคุณจะรู้สิ่งนี้ ตามที่คุณพูดไปโดยไม่มีstrมันจะทำงาน :) @MehdiDehghani
Sarath Avanavu

1
ฉันรู้ว่าไม่จำเป็นต้องทำงานในองค์กรใด ๆ เพื่อทราบเกี่ยวกับการตั้งชื่ออนุสัญญาแม้ว่าอนุสัญญานี้เรียกว่าสัญกรณ์ฮังการีและเป็นหนึ่งในอนุสัญญาการตั้งชื่อที่ไม่ดีและเลิกใช้แล้ว พิเศษสำหรับ C #
Mehdi Dehghani

55

ฉันใช้วิธีนี้สำเร็จแล้ว:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

คุณจะต้องส่งวัตถุที่ส่งคืนไปยังประเภทวัตถุที่คุณต้องการ


9
ฉันพยายามจินตนาการถึงสถานการณ์ที่การสร้างวัตถุด้วยชื่อคลาสแล้วหล่อมันเป็นประเภทนั้นจะทำให้ความรู้สึกใด ๆ เลย
MusiGenesis

13
ฉันเห็นสิ่งที่คุณหมายถึง ดูเหมือนซ้ำซ้อน ถ้าคุณรู้ชื่อคลาสทำไมคุณต้องใช้สตริงแบบไดนามิก สถานการณ์หนึ่งอาจเป็นได้ว่าการส่งไปยังคลาสพื้นฐานและสตริงแสดงถึงการสืบทอดของคลาสฐานนั้น
Ray Li

4
หากทราบคลาสฐานคุณสามารถใช้คลาสฐานหรืออินเทอร์เฟซของมันเป็นอาร์กิวเมนต์เพื่อส่งผ่านการสืบทอดโดยไม่มีการสะท้อนกลับ
Garet Claborn

3
สถานการณ์ที่มีประโยชน์: คุณต้องการเฉพาะอินเตอร์เฟสการทำให้เป็นอนุกรมหรืออินเทอร์เฟซทั่วไปอื่น ๆ คุณจะไม่ทิ้งมันลงไปในชั้นเรียน แต่อย่างน้อยก็เพื่ออะไรที่มากกว่าสิ่งของ
Harald Coppoolse

2
วิธีการโยนจากสตริงที่กำหนด ?
59

23

น่าจะเป็นคำถามของฉันควรจะเฉพาะเจาะจงมากขึ้น ฉันรู้คลาสพื้นฐานสำหรับสตริงดังนั้นแก้ไขโดย:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

ชั้น Activator.CreateInstance มีวิธีการต่าง ๆ เพื่อให้ได้สิ่งเดียวกันในวิธีที่ต่างกัน ฉันสามารถโยนมันเป็นวัตถุ แต่สิ่งที่กล่าวมาข้างต้นมีประโยชน์กับสถานการณ์ของฉันมากที่สุด


4
แทนที่จะตอบกลับในส่วนคำถามเราขอแนะนำให้คุณแก้ไขคำถามและบันทึกการเปลี่ยนแปลง คุณจะได้รับคำตอบมากขึ้น / ดีขึ้นสำหรับการทำมัน
Jason Jackson

ขอขอบคุณที่โพสต์บรรทัดรหัสเฉพาะที่เหมาะกับคุณ การเรียงลำดับเกินจำนวน CreateInstance ทั้งหมดและวิธีสร้างประเภทต่าง ๆ ใช้เวลามากซึ่งคุณได้ช่วยฉันไว้
Ethel Evans

4

ฉันรู้ว่าฉันมาช้าไปกับเกม ... แต่วิธีแก้ปัญหาที่คุณกำลังมองหาอาจเป็นการรวมกันของข้างต้นและใช้อินเทอร์เฟซเพื่อกำหนดแง่มุมที่สาธารณชนสามารถเข้าถึงวัตถุของคุณได้

จากนั้นถ้าคลาสทั้งหมดของคุณที่จะสร้างวิธีนี้ใช้อินเทอร์เฟซนั้นคุณก็สามารถส่งเป็นประเภทอินเตอร์เฟสและทำงานกับวัตถุผลลัพธ์


4

ในการสร้างอินสแตนซ์ของคลาสจากโครงการอื่นในโซลูชันคุณสามารถขอรับแอสเซมบลีที่ระบุโดยชื่อของคลาสใด ๆ (เช่น BaseEntity) และสร้างอินสแตนซ์ใหม่:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");

3

ตัวอย่างเช่นหากคุณเก็บค่าประเภทต่าง ๆ ในฟิลด์ฐานข้อมูล (เก็บไว้เป็นสตริง) และมีฟิลด์อื่นที่มีชื่อประเภท (เช่น String, bool, int, MyClass) จากนั้นจากข้อมูลของเขตข้อมูลนั้นคุณสามารถทำได้ สร้างคลาสประเภทใดก็ได้โดยใช้โค้ดด้านบนและเติมด้วยค่าจากฟิลด์แรก แน่นอนนี้ขึ้นอยู่กับประเภทที่คุณกำลังเก็บมีวิธีการแยกสตริงเป็นประเภทที่ถูกต้อง ฉันใช้หลายครั้งในการจัดเก็บการตั้งค่าผู้ใช้ในฐานข้อมูล


-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

ทำไมคุณถึงต้องการเขียนรหัสเช่นนี้? หากคุณมีคลาส 'ReportClass' คุณสามารถสร้างอินสแตนซ์ของมันได้โดยตรงตามที่แสดงด้านล่าง

ReportClass report = new ReportClass();

รหัสReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));จะถูกใช้เมื่อคุณไม่มีคลาสที่จำเป็น แต่คุณต้องการสร้างอินสแตนซ์และหรือหรือเรียกใช้เมธอดแบบไดนามิก

ฉันหมายความว่ามันจะเป็นประโยชน์เมื่อ u รู้การชุมนุม แต่ในขณะที่เขียนรหัสที่คุณไม่ได้มีชั้นเรียนReportClassที่มีอยู่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.