2010-08-08 40 views
22

Trong kiến ​​trúc plugin của tôi, tôi hiện đang truyền một tên plugin (chuỗi), tên phương thức (chuỗi) và tham số (mảng đối tượng) vào dịch vụ plugin của tôi để thực thi phương thức đã chỉ định và trả về kết quả (của gõ T).Chuyển kiểu ẩn danh làm tham số phương thức

phương thức execute Các dịch vụ Plugin có thể được nhìn thấy dưới đây:

public TResult Execute<TResult>(string pluginName, string operation, params object[] input) { 
    MethodInfo method = null; 
    TResult result = default(TResult); 

    var plugin = _plugins.Enabled().FirstOrDefault(x => x.GetType().Name.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase)); 

    if (plugin != null) { 
     method = plugin.GetType().GetMethods().FirstOrDefault(x => x.Name == operation); 
     if (method != null) { 
      result = (TResult)method.Invoke(plugin, input); 
     } 
    } 
    return result; 
    } 

Một cách sử dụng ví dụ:

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin", 
    "GetImageUrl", 
    new object[] { image, size }); 

Những gì tôi thà làm là vượt qua trong một loại vô danh thay vì (như tôi nghĩ rằng đây là dễ đọc hơn) tức là

var url = AppHelper.PluginService.Execute<string>(
    "ImagePlugin", 
    "GetImageUrl", 
    new { image = image, targetSize = size }); 

Làm cách nào để thay đổi phương thức Execute để ánh xạ ype thuộc tính để tham số phương pháp plugin của tôi?

Tôi đã xem xét sử dụng loại động mới trong .net 4.0 nhưng tôi muốn xác định tham số của mình trên phương thức plugin thay vì chấp nhận một đối tượng động.

Cảm ơn Bến

[Cập nhật]

Sau khi xem qua mã nguồn ASP.NET MVC có vẻ như đủ đơn giản để kéo loại vô danh thành một cuốn từ điển đối tượng ví dụ RouteValueDictionary. Với sự trợ giúp của sự phản chiếu, biểu thức LINQ được tạo động. Mặc dù thực hiện tốt, tôi thực sự không muốn tất cả sự phức tạp thêm này.

Theo những nhận xét dưới đây, tôi có thể đạt được khả năng đọc chỉ bằng cách xác định các thông số inline của tôi (không cần khai báo mảng đối tượng):

var url = AppHelper.PluginService.Execute<string>("ImagePlugin", "GetImageUrl", image, size); 
+2

Vì bạn đang sử dụng từ khóa 'params', bạn có thể làm' hình ảnh, kích thước' thay vì 'đối tượng mới [] {image, size}'. Nó sẽ làm cho nó dễ đọc hơn, và vì các phương thức 'Invoke' chấp nhận mảng đối tượng, tôi sẽ để lại chữ ký phương thức như nó. – Necros

Trả lời

9

Có một số cách để làm điều này có thể mặc dù tôi sẽ không tư vấn cho bất kỳ ai trong số họ.

Trước tiên, bạn có thể sử dụng sự phản chiếu có nghĩa là bạn phải viết nhiều mã bổ sung (dễ bị lỗi) trong phương pháp PluginService.Execute để nhận các giá trị bạn muốn.

Thứ hai, nếu bạn biết thông số của loại ẩn danh bạn đang chuyển sang phương pháp, bạn có thể sử dụng kỹ thuật được mô tả here. Bạn có thể truyền sang một loại ẩn danh khác bên trong phương thức có cùng thuộc tính. Here là một mô tả về kỹ thuật tương tự từ Jon Skeet.

Thứ ba, bạn có thể sử dụng các lớp học từ System.ComponentModel.Ví dụ, ASP.NET MVC sử dụng điều này. Nó sử dụng sự phản chiếu dưới mui xe. Tuy nhiên, trong ASP.NET MVC hoặc tên thuộc tính nổi tiếng (ví dụ: controlleraction) hoặc tên của chúng không quan trọng vì chúng được chuyển như một phương pháp điều khiển (ví dụ: id).

+0

Ronald, cảm ơn liên kết. Bắt đầu nghĩ rằng tôi nên dính vào thực hiện hiện tại của tôi. Tuy nhiên, đây không phải là cái gì đó được sử dụng rộng rãi trong ASP.NET MVC, ví dụ như trong HTML helpers và trong định tuyến. Tôi chắc chắn phải có một cách "tốt" để làm điều này nếu không Microsoft sẽ không làm điều đó :) –

+0

Điểm tốt. Tôi đã cập nhật câu trả lời của mình bằng một cách khác để làm những gì bạn muốn. –

+0

Tôi đã đánh dấu câu trả lời của bạn là câu trả lời vì câu trả lời là câu trả lời hoàn chỉnh nhất.Tuy nhiên, sau khi xem qua mã nguồn MVC để xem cách họ đạt được điều này, tôi sẽ gắn bó với việc thực hiện của mình nhưng sử dụng đề xuất của Necros để cải thiện khả năng đọc. –

1

Tôi đã làm điều này một lần. Những gì bạn có thể làm là lấy các tham số được mong đợi từ hàm thông qua sự phản chiếu. Sau đó, bạn có thể xây dựng mảng tham số của mình bằng cách khớp các tên trong mảng tham số với các khóa của đối tượng ẩn danh.

Hy vọng rằng sẽ giúp :-).

0

Trước hết, hãy kiểm tra không gian tên System.Addin, bạn có thể nhận được trợ giúp ở đó.

Thứ hai, bạn có thể tạo giao diện của riêng mình bằng tên và thông số phương thức cụ thể và để plugin triển khai giao diện. Bạn có thể định nghĩa giao diện plugin trong một dự án khác có thể được tham chiếu trong cả ứng dụng lẫn dự án plugin.

+0

Chúng tôi đã sử dụng giao diện cùng với StructureMap để gọi các loại plugin cụ thể. Điều này là nhiều hơn cho các plugin mà người dùng có thể tạo khi đang di chuyển và muốn sử dụng trong giao diện người dùng (ví dụ: họ có thể muốn trao đổi ImagePlugin ở trên để tạo hình ảnh từ Amazon S3) –

21

Cuối cùng tôi đã bắt gặp this post minh họa bằng cách sử dụng các loại ẩn danh làm từ điển. Sử dụng phương thức này, bạn có thể chuyển kiểu ẩn danh như một tham số phương thức (đối tượng) và truy cập các thuộc tính của nó.

Tuy nhiên, tôi cũng muốn nói thêm rằng sau khi nhìn vào tính năng động mới trong .net 4.0 như ExpandoObject, nó cảm thấy sạch hơn nhiều để vượt qua một đối tượng động như một tham số:

 dynamic myobj = new ExpandoObject(); 
     myobj.FirstName = "John"; 
     myobj.LastName = "Smith"; 

     SayHello(myobj); 
     ........... 

     public static void SayHello(dynamic properties) 
     { 
      Console.WriteLine(properties.FirstName + " " + properties.LastName); 
     } 
12

Sử dụng đối tượng động cho thông số nếu bạn muốn chuyển loại ẩn danh. Phương thức thực hiện của một plugin sẽ mong đợi các thuộc tính nhất định của một đối tượng tham số để làm việc. Bằng cách sử dụng từ khóa động C# trình biên dịch sẽ được hướng dẫn để không thực hiện kiểm tra kiểu trên một tham số và sẽ cho phép sử dụng cú pháp gõ mạnh trong mã plugin. Độ phân giải tên thuộc tính sẽ xảy ra trong thời gian chạy và nếu một đối tượng được truyền không có các thuộc tính như vậy thì một ngoại lệ sẽ được ném ra.

var o = new { FirstName = "John", LastName = "Doe" }; 

var result = MyMethod(o); 

string MyMethod(dynamic o) 
{ 
    return o.FirstName + " " + o.LastName; 
} 

Read more in this blog post

7

Ví dụ này chuyển đổi đối tượng nặc danh cho một cuốn từ điển:

IDictionary<string, object> AnonymousObjectToDictionary(object propertyBag) 
{ 
    var result = new Dictionary<string, object>(); 
    if (propertyBag != null) 
    { 
     foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(propertyBag)) 
     { 
      result.Add(property.Name, property.GetValue(propertyBag)); 
     } 
    } 
    return result; 
} 

Bạn có thể gọi nó như thế này:

AnonymousObjectToDictionary(new { foo = 11, bar = "Be happy" }); 
3

Nếu nó là một loại anonomous từ LINQ, sau đó bạn có thể dễ dàng làm điều này bằng cách chuyển qua IEnumerable.

Dưới đây là một ví dụ về một phương pháp nhận

public static void MyMethod<IEnumType>(ref IEnumerable<IEnumType> ienum) 
    { 
     using (DataTable dt = new DataTable()) 
     { 
      ienum.First(ie => true).GetType().GetProperties().ToList().ForEach(pr => dt.Columns.Add(pr.Name, typeof(string))); //Parallelization not possible since DataTable columns must be in certain order 

      ienum.ToList().ForEach(ie => //Parallelization not possible since DataTable rows not synchronized. 
       { 
        List<object> objAdd = new List<object>(); 
        ie.GetType().GetProperties().ToList().ForEach(pr => objAdd.Add(ie.GetType().InvokeMember(pr.Name, BindingFlags.GetProperty, null, ie, null))); //Parallelization not possible since DataTable columns must be in certain order 
        dt.Rows.Add(objAdd.ToArray()); 
        objAdd.Clear(); 
        objAdd = null; 
       }); 
      //Do something fun with dt 
     } 
    } 

Tất nhiên, kể từ khi bạn đang sử dụng phản ánh sau đó bạn có thể thấy vấn đề hiệu suất trên machiens chậm hoặc nơi bạn có hoặc là một IEnumerable lớn hoặc nhiều thuộc tính trong T.

1
public static void ExAnonymousType() 
{ 
    var nguoi = new { Ten = "Vinh", Tuoi = 20 }; 
    Console.WriteLine(nguoi.Ten + " " + nguoi.Tuoi); 
    DoSomeThing(nguoi); 

} 

private static void DoSomeThing(object nguoi) 
{ 
    Console.WriteLine(nguoi.GetType().GetProperty("Ten").GetValue(nguoi,null)); 
} 
Các vấn đề liên quan