2009-06-11 28 views
47

Tôi đang trong tình huống mà tôi muốn khởi tạo một đối tượng thuộc loại sẽ được xác định khi chạy. Tôi cũng cần phải thực hiện một diễn viên rõ ràng cho loại đó.Khởi tạo một đối tượng với kiểu xác định thời gian chạy

Something như thế này:

static void castTest(myEnum val) 
{ 
    //Call a native function that returns a pointer to a structure 
    IntPtr = someNativeFunction(..params..); 

    //determine the type of the structure based on the enum value 
    Type structType = getTypeFromEnum(val); 

    structType myStruct = (structType)Marshal.PtrToStructure(IntPtr, structType); 
} 

này rõ ràng là không mã hợp lệ, nhưng tôi hy vọng nó truyền tải được bản chất của những gì tôi đang cố gắng làm. Phương pháp tôi đang thực sự làm việc trên sẽ phải thực hiện hoạt động marshaling trên ~ 35 loại khác nhau. Tôi có một số phương pháp khác mà sẽ cần phải làm một cái gì đó tương tự với cùng một tập hợp các loại. Vì vậy, tôi muốn tách biệt logic xác định loại từ các phương thức này để tôi chỉ cần viết nó một lần và để các phương thức luôn sạch sẽ và dễ đọc.

Tôi phải thừa nhận là một người mới làm quen với thiết kế. Bất cứ ai có thể đề xuất một cách tiếp cận tốt cho vấn đề này? Tôi nghi ngờ có thể có một mẫu thiết kế thích hợp mà tôi không biết.

+1

lẽ http://msdn.microsoft.com/en- chúng tôi/thư viện/system.activator.aspx có thể giúp bạn?Nó thường hữu ích cho việc khởi tạo các đối tượng có kiểu mà bạn chỉ biết khi chạy. Nó có thể được thực hiện với Reflection thường xuyên nhưng nó có một chút fiddlier. Tôi không có ý tưởng về thiết kế của bạn mặc dù vậy tôi sẽ không trả lời. – Skurmedel

+1

có thể trùng lặp của [Lấy một đối tượng mới từ một Loại] (http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type) – nawfal

Trả lời

97

Có một số cách bạn có thể tạo một đối tượng của một loại nhất định khi đang bay, một là:

// determine type here 
var type = typeof(MyClass); 

// create an object of the type 
var obj = (MyClass)Activator.CreateInstance(type); 

Và bạn sẽ nhận được một ví dụ của MyClass trong obj.

Một cách khác là sử dụng phản ánh:

// get type information 
var type = typeof(MyClass); 

// get public constructors 
var ctors = type.GetConstructors(BindingFlags.Public); 

// invoke the first public constructor with no parameters. 
var obj = ctors[0].Invoke(new object[] { }); 

Và từ một trong ConstructorInfo trở lại, bạn có thể "Invoke()" nó với lập luận và nhận được trở lại một thể hiện của lớp như thể bạn đã sử dụng một toán tử "mới".

+12

Điều này không trả lời được câu hỏi (hoàn toàn). Anh ta không biết tại thời gian biên dịch nếu nó sẽ là 'MyClass' hoặc' HisClass' hoặc 'HerClass' (kiểu xác định thời gian chạy). – Bitterblue

+4

@ mini-me Lưu ý rằng trong câu hỏi OP bao gồm 'Kiểu structType = getTypeFromEnum (val);'. Tôi chỉ cần thêm một mã ví dụ để chứng minh rằng một trong những nên lấy dụ 'Loại' đầu tiên. – chakrit

+0

Bạn không chắc chắn nếu bạn có điều đó: Tôi đã chỉ trích phần diễn xuất trong câu trả lời của bạn. Câu trả lời của Rex M đưa ra một giải pháp làm việc đầy đủ + tham khảo một cách khác bằng cách sử dụng động lực học. – Bitterblue

9

Tôi nghĩ rằng bạn đang tìm kiếm Activator.CreateInstance

+1

Vâng, tôi cũng vậy. Tôi đã sử dụng nó để được giúp đỡ. http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type-in-c –

10

Bạn có thể chủ yếu là làm những gì bạn mô tả, nhưng vì bạn không biết loại thời gian biên dịch, bạn sẽ phải giữ trường hợp được nhập sai; kiểm tra loại của nó tại mỗi điểm bạn sử dụng nó, và đúc nó một cách thích hợp sau đó (điều này sẽ không cần thiết với C# 4.0, hỗ trợ dynamics):

Type type = CustomGetTypeMethod(); 
var obj = Activator.CreateInstance(type); 

... 


if(obj is MyCustomType) 
{ 
    ((MyCustomType)obj).Property1; 
} 
else if (obj is MyOtherCustomType) 
{ 
    ((MyOtherCustomType)obj).Property2; 
} 
5

Tạo một thể hiện của một thời gian chạy xác định Type rất dễ dàng, sử dụng Activator.CreateInstance, như những người khác đã đề cập. Tuy nhiên, hãy đúc nó, như bạn làm trong ví dụ của bạn trên dòng Marshal.PtrToStructure là không thể, vì loại này phải được biết tại thời gian biên dịch để truyền. Ngoài ra, lưu ý rằng không thể sử dụng Activator.CreateInstance kết hợp với IntPtr.

Nếu các loại của bạn có một lớp cơ sở chung (trừ Object), bạn có thể truyền đến loại cơ sở và chức năng gọi trên đó. Nếu không, các chức năng gọi điện sẽ chỉ có thể sử dụng sự phản chiếu.

Vì vậy, một trong hai:

static void castTest(myEnum val) 
{ 
    //Call a native function that returns a pointer to a structure 
    IntPtr val = someNativeFunction(..params..); 

    //determine the type of the structure based on the enum value 
    Type structType = getTypeFromEnum(val); 

    BaseClass myStruct = (BaseClass)Marshal.PtrToStructure(IntPtr, structType); 
    myStruct.SomeFunctionDeclaredInBaseClass(); 
} 

Hoặc:

static void castTest(myEnum val) 
{ 
    //Call a native function that returns a pointer to a structure 
    IntPtr val = someNativeFunction(..params..); 

    //determine the type of the structure based on the enum value 
    Type structType = getTypeFromEnum(val); 

    object myStruct = Marshal.PtrToStructure(IntPtr, structType); 
    MemberInfo[] function = FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, 
    (MemberFilter)delegate(MemberInfo info, object filter) 
    { 
     return info.Name == filter.ToString(); 
    }, "SomeFunction"); 
    if (mi.Length > 0 && mi[0] is MethodInfo) 
    ((MethodInfo)mi[0]).Invoke(myStruct, ..params..); 
} 
+0

+1. Ý tưởng hữu ích hơn của Aistina là xác định một lớp cơ sở hoặc giao diện và làm bất cứ công việc nào cần thiết chống lại điều đó thay vì chỉ tạo ra một thể hiện của một kiểu xác định thời gian chạy – Evan

0

Bạn có thể đi động:

using System; 

namespace TypeCaster 
{ 
    class Program 
    { 
     internal static void Main(string[] args) 
     { 
      Parent p = new Parent() { name = "I am the parent", type = "TypeCaster.ChildA" }; 
      dynamic a = Convert.ChangeType(new ChildA(p.name), Type.GetType(p.type)); 
      Console.WriteLine(a.Name); 

      p.type = "TypeCaster.ChildB"; 
      dynamic b = Convert.ChangeType(new ChildB(p.name), Type.GetType(p.type)); 
      Console.WriteLine(b.Name); 
     } 
    } 

    internal class Parent 
    { 
     internal string type { get; set; } 
     internal string name { get; set; } 

     internal Parent() { } 
    } 

    internal class ChildA : Parent 
    { 
     internal ChildA(string name) 
     { 
      base.name = name + " in A"; 
     } 

     public string Name 
     { 
      get { return base.name; } 
     } 
    } 

    internal class ChildB : Parent 
    { 
     internal ChildB(string name) 
     { 
      base.name = name + " in B"; 
     } 

     public string Name 
     { 
      get { return base.name; } 
     } 
    } 
} 
-2
methodName = NwSheet.Cells[rCnt1, cCnt1 - 2].Value2; 
          Type nameSpace=typeof(ReadExcel); 
          Type metdType = Type.GetType(nameSpace.Namespace + "." + methodName); 
          //ConstructorInfo magicConstructor = metdType.GetConstructor(Type.EmptyTypes); 
          //object magicClassObject = magicConstructor.Invoke(new object[] { }); 
          object magicClassObject = Activator.CreateInstance(metdType); 
          MethodInfo mthInfo = metdType.GetMethod("fn_"+methodName); 
          StaticVariable.dtReadData.Clear(); 
          for (iCnt = cCnt1 + 4; iCnt <= ShtRange.Columns.Count; iCnt++) 
          { 
           temp = NwSheet.Cells[1, iCnt].Value2; 
           StaticVariable.dtReadData.Add(temp.Trim(), Convert.ToString(NwSheet.Cells[rCnt1, iCnt].Value2)); 
          } 


          //if (Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_AddNum" || Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_SubNum") 
          //{ 
          // //StaticVariable.intParam1 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 4].Value2); 
          // //StaticVariable.intParam2 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 5].Value2); 
          // object[] mParam1 = new object[] { Convert.ToInt32(StaticVariable.dtReadData["InParam1"]), Convert.ToInt32(StaticVariable.dtReadData["InParam2"]) }; 
          // object result = mthInfo.Invoke(this, mParam1); 
          // StaticVariable.intOutParam1 = Convert.ToInt32(result); 
          // NwSheet.Cells[rCnt1, cCnt1 + 2].Value2 = Convert.ToString(StaticVariable.intOutParam1) != "" ? Convert.ToString(StaticVariable.intOutParam1) : String.Empty; 
          //} 

          //else 
          //{ 
           object[] mParam = new object[] { }; 
           mthInfo.Invoke(magicClassObject, mParam); 
Các vấn đề liên quan