2009-02-19 37 views
6

Tôi hiện đang có loại mã:C#: Đúc các loại động

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    if (MainObject is SomeClassType1) 
    { 
     SomeClassType1 HelpObject = (SomeClassType1)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     SomeClassType2 HelpObject = (SomeClassType2)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
} 

Giả sử rằng SomeClassType1 và SomeClassType2 có cùng một bộ tài sản mà tôi muốn gán (mặc dù họ có thể khác nhau ở những người khác), là có thể tự động cast MainObject vào loại thích hợp và sau đó gán giá trị, mà không sao chép mã? Đây là những gì tôi muốn nhìn thấy cuối cùng:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type DynamicType = null; 

    if (MainObject is SomeClassType1) 
    { 
     DynamicType = typeof(SomeClassType1); 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     DynamicType = typeof(SomeClassType2); 
    } 

    DynamicType HelpObject = (DynamicType)MainObject; 
    HelpObject.Property1 = Arg1; 
    HelpObject.Property2 = Arg2; 
} 

Và rõ ràng là C# phàn nàn về việc không thể tìm DynamicType:

Loại hoặc namespace tên 'DynamicType' không thể tìm được (bạn có thiếu chỉ thị sử dụng hoặc tham chiếu lắp ráp không?)

Có điều gì giống như vậy trong C# 2.0 không? Nếu nó lộn xộn hơn mã hiện tại của tôi, hơn là tôi không thấy điểm nào trong việc này, nhưng tôi rất muốn tìm hiểu. Cảm ơn!

EDIT: Chỉ cần làm rõ, tôi hoàn toàn hiểu rằng việc triển khai giao diện là giải pháp thích hợp nhất và có thể đúng. Điều đó nói rằng, tôi quan tâm nhiều hơn đến việc xem làm thế nào để tôi có thể làm điều đó mà không cần thực hiện một giao diện. Cảm ơn bạn đã trả lời tuyệt vời!

Trả lời

15

Có vẻ như cả hai loại bạn quan tâm đều triển khai cùng hai thuộc tính. Trong trường hợp đó, những gì bạn muốn làm là xác định giao diện cho các thuộc tính đó:

public interface IMyInterface 
{ 
    public Foo Property1 {get; set;} 
    public Bar Property2 {get;set;} 
} 

Sau đó, đảm bảo mỗi lớp của bạn thông báo cho trình biên dịch rằng họ triển khai giao diện mới đó. Cuối cùng, sử dụng một phương pháp chung với một đối số kiểu đó là hạn chế để interace rằng:

private void FillObject<T>(T MainObject, Foo Arg1, Bar Arg2) 
    where T : IMyInterface 
{ 
    MainObject.Property1 = Arg1; 
    MainObject.Property2 = Arg2; 
} 

Lưu ý rằng ngay cả với mã thêm để khai báo giao diện, những đoạn vẫn kết thúc ngắn hơn hoặc một trong những đoạn bạn được đăng trong câu hỏi và mã này dễ dàng hơn để mở rộng nếu số lượng loại bạn quan tâm tăng lên.

+1

+1 Nice ... Tôi sẽ không nghĩ đến việc sử dụng Generics, tôi sẽ chỉ cast vào giao diện. –

+0

Thông số chung T hữu ích ở đây như thế nào? Tại sao không chỉ đơn giản là sử dụng FillObject (IMyInterface mainobject, ...)? –

+0

Tôi tò mò - tại sao bạn sử dụng generics trong trường hợp này và không chỉ riêng void FillObject (IMyInterface MainObject, Foo Arg1, Bar Arg2)? –

9

Về cơ bản những gì bạn đang làm ở đây là viết một câu lệnh chuyển đổi dựa trên loại cho đối tượng. Không có cách nào tốt đẹp để làm điều này khác hơn là ví dụ đầu tiên của bạn (đó là tẻ nhạt lúc tốt nhất).

Tôi đã viết một khuôn khổ nhỏ để bật các loại làm cho cú pháp ngắn gọn hơn một chút. Nó cho phép bạn viết mã như sau.

TypeSwitch.Do(
    sender, 
    TypeSwitch.Case<Button>(
     () => textBox1.Text = "Hit a Button"), 
    TypeSwitch.Case<CheckBox>(
     x => textBox1.Text = "Checkbox is " + x.Checked), 
    TypeSwitch.Default(
     () => textBox1.Text = "Not sure what is hovered over")); 

Blog Post: http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

2

Thay vì cố gắng đúc, có lẽ bạn có thể thử thiết lập các thuộc tính sử dụng phản ánh.

4
private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type t = MainObject.GetType(); 

    t.GetProperty("Property1").SetValue(MainObject, Arg1, null); 
    t.GetProperty("Property2").SetValue(MainObject, Arg2, null); 
} 
+0

Tôi nghĩ rằng generics thích hợp hơn ở đây, nhưng ít nhất tôi sẽ kiểm tra để đảm bảo các thuộc tính tồn tại trước tiên. –

+0

Tôi chỉ muốn chứng minh cách bạn làm điều đó với sự phản chiếu. Đây không phải là cách tiếp cận * hoàn thành * hoặc * được đề xuất * cho vấn đề này. –

+0

Tôi nghĩ rằng điều này có thiên tai được viết trên tất cả ... –

7

Bạn có thể thực hiện thay đổi đối với SomeClassType1, SomeClassType2 etc không? Nếu có thì tôi sẽ đề nghị bạn tạo một giao diện chứa các thuộc tính chung của bạn và sau đó được nhập vào giao diện này trong vòng FillObject() để đặt thuộc tính.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SO566510 
{ 
    interface IMyProperties 
    { 
     int Property1 { get; set; } 
     int Property2 { get; set; } 
    } 

    class SomeClassType1 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 

    class SomeClassType2 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj1 = new SomeClassType1(); 
      var obj2 = new SomeClassType2(); 

      FillObject(obj1, 10, 20); 
      FillObject(obj2, 30, 40); 

     } 

     private static void FillObject(IMyProperties objWithMyProperties 
            , int arg1, int arg2) 
     { 
      objWithMyProperties.Property1 = arg1; 
      objWithMyProperties.Property2 = arg2; 
     } 
    } 
} 
+0

Trong khi đó chắc chắn là một lựa chọn, nó sẽ là một overkill cho điều đơn giản tôi đang cố gắng để đạt được. Mã của tôi về cơ bản là những gì tôi đã đăng ở trên, chỉ với một vài loại và tên biến được thay đổi. –

+0

Tôi sắp sửa đề xuất như vậy. Nếu chúng có cùng thuộc tính công khai, Giao diện có vẻ phù hợp. –

+0

@MK_Dev: Nó không phải là nhiều công việc bạn nghĩ rằng nó là, bạn cần phải cung cấp cho nó một thử. Trong thực tế nó có thể sẽ làm giảm kích thước của mã của bạn. –

3

Một số ý tưởng:

  1. Có cả hai loại kế thừa từ các loại tương tự mà có tài sản chung
  2. Có cả hai loại thực hiện các giao diện tương tự mà có tài sản chung
  3. Sử dụng phản ánh để thiết lập các thuộc tính thay vì đặt chúng trực tiếp (điều này có thể xấu hơn giá trị của nó)
  4. Sử dụng dynamic feature mới, tôi chưa thử, nhưng có vẻ như nó có thể giải quyết vấn đề của bạn
0

Tôi đang tự động đúc đối tượng bằng cách sử dụng Phản chiếu trong ứng dụng ASP.NET MVC. Về cơ bản tôi liệt kê các thuộc tính của một lớp, tìm giá trị tương ứng trong kho dữ liệu và tự động đúc giá trị và gán nó cho cá thể đối tượng. Xem bài đăng trên blog của tôi Dynamic Casting with .NET