2015-09-21 14 views
8

Tôi đang cố gắng cải thiện mã phản chiếu của mình bằng cách tạo đại biểu cho các phương pháp GetterSetter.Đúc một đại biểu vào một hành động <T> hoặc Func <T> trong thời gian chạy

Mã của tôi trông như thế này:

MyObject obj = new MyObject(); 
var prop = obj.GetType().GetProperty("Prop"); 
var getType = typeof(Func<>).MakeGenericType(prop.PropertyType); 
var setType = typeof(Action<>).MakeGenericType(prop.PropertyType); 

var getMethod = prop.GetGetMethod().CreateDelegate(getType, obj); 
var setMethod = prop.GetSetMethod().CreateDelegate(setType, obj); 

// I'd like to change this section and not to use a dynamic!! 
dynamic castedGet = Convert.ChangeType(getMethod, getType); 
dynamic castedSet = Convert.ChangeType(setMethod, setType); 

CreateDelegate trả về một Delegate và sử dụng DynamicInvokekhông phải là hiệu suất khôn ngoan.

Tôi được đúc (mã hoá) Delegate thành Action<T> \ Func<T> và thấy hiệu suất của tôi tăng rất lớn.

sau đó tôi đã cố gắng để đúc các Delegate vào Action<T> \ Func<T> trong thời gian chạy (sử dụng Convert.ChangeTypedynamic) và hiệu suất của tôi bị tổn thương - có thể là do thực tế là tôi đang sử dụng một loại dynamic.

Tôi khá chắc chắn rằng tôi có thể thực hiện việc này mà không cần dynamic.

tôi đoán giải pháp có cái gì để làm với expression trees, nhưng tôi không thực sự chắc chắn làm thế nào để mã hóa một cái gì đó như thế này. Nếu ai đó có giải pháp tốt không sử dụng số expression trees thì cũng sẽ rất thú vị khi nghe về giải pháp đó.

+0

Bạn có đang thực thi tất cả mã này * mọi lần * hay bộ nhớ đệm đại biểu ở đâu đó và sau đó gọi cho họ không? – Dai

+0

@Dai - Đây là một phần nhỏ của mã của tôi và loại mẫu. Tôi đang tìm kiếm để cache các propertyinfo, getter, setter cho mỗi tài sản - một cách lười biếng. –

+0

Tại sao bạn vẫn sử dụng 'dynamic'? 'Convert.ChangeType' không trả về một đối tượng bị ràng buộc trễ. – Dai

Trả lời

3

Nếu mục tiêu của bạn là để có thể gọi hành động của bạn/chức năng mà không biết kiểu trả tại thời gian biên dịch, sau đó bạn có thể muốn kết thúc với một số Action<object>Func<object>, phải không?

Bạn có thể làm điều này mà không cần phải biên dịch một cây biểu hiện hay bất cứ điều gì, như vậy:

// Use reflection to create the action, invoking the method below. 
var setAction = (Action<object>) this.GetType() 
    .GetMethod("CastAction", BindingFlags.Static | BindingFlags.NonPublic) 
    .MakeGenericMethod(prop.PropertyType) 
    .Invoke(null, new object[]{setMethod}); 

// invoke the action like this: 
object value = 42; // or any value of the right type. 
setAction(value); 

Sử dụng phương pháp helper này:

private static Action<object> CastAction<T>(Delegate d) 
{ 
    var action = (Action<T>)d; 
    return obj => action((T)obj); 
} 

xét nghiệm của tôi cho thấy điều này là khoảng 25% nhanh hơn so với sử dụng dynamic và chậm hơn khoảng 45% so với chỉ nói obj.Prop = 2;

+0

Sự khác biệt giữa câu trả lời @ k3b là gì? OP nói rằng "Sử dụng MethodInfo.Invoke chậm hơn rất nhiều so với việc tạo các đại biểu và gọi chúng" –

+0

@codroipo: Trong trường hợp này, tôi đang sử dụng 'MethodInfo.Invoke()' chỉ để tạo đại biểu ngay từ đầu. Đây là điều mà phương thức 'ChangeType' của OP thực hiện có hiệu quả dưới các trang bìa. Hành động 'setAction' kết quả, tuy nhiên, có thể được gọi nhanh hơn nhiều so với gọi' setter.Invoke() ', như câu trả lời của k3b. Và nó hơi nhanh hơn gọi hành động 'castedSet' động, bởi vì nó không dựa vào lời gọi động. – StriplingWarrior

+1

@StriplingWarrior - Điều này rất thú vị. Điểm chuẩn tốt hơn là sử dụng động và chậm hơn so với sử dụng tính năng tạo mã được mã hóa cứng. Hiện tại, đây là cách nhanh nhất mà tôi có. Cảm ơn bạn vì câu trả lời. Tôi đang chờ đợi thêm một số câu trả lời và sẽ chấp nhận nếu không có gì tốt hơn. Cảm ơn!!!! +1. –

1

Có lý do nào bạn cần sử dụng Action < T> hoặc Func < T> để tự động nhận/đặt tính thích hợp không?

Nếu không bạn có thể sử dụng PropertyInfo.GetMethod() và SetMethod()

MyObject obj = new MyObject(); 
PropertyInfo prop = obj.GetType().GetProperty("Prop"); 

MethodInfo getter = prop.GetMethod(); 
getter.Invoke(...) 

MethodInfo setter = prop.SetMethod(); 
setter.Invoke(...) 
+0

Lý do là hiệu suất. Sử dụng MethodInfo.Invoke chậm hơn rất nhiều so với việc tạo các delegate và gọi chúng (giả sử rằng tôi muốn cache chúng). Dù sao cũng cảm ơn bạn. –

+1

Tôi đã không nhận thức được (và không bao giờ nghĩ đến và không bao giờ kiểm tra bản thân mình) rằng 'Invoke()' là chậm hơn so với ducktyping sử dụng 'năng động ' – k3b

Các vấn đề liên quan