Imagine mã đơn giản sau đây:Làm thế nào để đúc một giá trị của loại chung T để tăng gấp đôi mà không có quyền anh?
public void F<T>(IList<T> values) where T : struct
{
foreach (T value in values)
{
double result;
if (TryConvertToDouble((object)value, out result))
{
ConsumeValue(result);
}
}
}
public void ConsumeValue(double value)
{
}
Vấn đề với đoạn code trên được đúc để phản đối, mà kết quả trong boxing trong vòng lặp.
Có cách nào để đạt được cùng chức năng, ví dụ: cho ăn ConsumeValue với tất cả các giá trị mà không cần đến boxing trong vòng lặp foreach không? Lưu ý rằng F phải là một phương pháp chung.
Tôi có thể sống với mã chuẩn bị tốn kém miễn là mã được thực hiện ngoài vòng lặp một lần. Ví dụ, nếu một phương pháp năng động ưa thích cần được phát ra, thì sẽ tốt nếu được thực hiện một lần.
EDIT
T là đảm bảo được một số loại số hoặc bool.
Động lực. Hãy tưởng tượng ứng dụng hướng dữ liệu meta, trong đó một tác nhân báo cáo luồng dữ liệu, nơi loại mục dữ liệu được tự động phát ra dựa trên dữ liệu meta luồng dữ liệu. Hãy tưởng tượng cũng có, đó là động cơ bình thường, mà biết để bình thường hóa các luồng dữ liệu số theo một số thuật toán. Loại luồng dữ liệu số đến chỉ được biết đến trong thời gian chạy và có thể được chuyển hướng đến một phương thức chung của kiểu dữ liệu đó. Bình thường, tuy nhiên, dự kiến tăng gấp đôi và sản xuất tăng gấp đôi. Đây là một mô tả mức độ rất cao, xin vui lòng không đi sâu vào nó.
EDIT2
Về các diễn viên sẽ tăng gấp đôi. Trên thực tế chúng ta có một phương pháp để chuyển đổi để tăng gấp đôi với chữ ký sau đây:
bool TryConvertToDouble(object value, out double result);
tôi nên đã sử dụng nó trong ví dụ ở nơi đầu tiên, nhưng tôi muốn tiết kiệm không gian và viết cái gì đó không được đi làm. Sửa lỗi ngay bây giờ. Cảm ơn vì đã chú ý.
EDIT3
Guys, việc thực hiện hiện tại không hộp các giá trị. Và ngay cả khi tôi không có phán quyết của profiler về hình phạt hiệu suất của nó (nếu có), tôi vẫn còn thú vị để biết liệu có một giải pháp mà không có quyền anh (và không chuyển đổi thành chuỗi). Hãy để tôi gọi nó là mối quan tâm hoàn toàn về mặt học thuật. Điều này thực sự quan tâm đến tôi, bởi vì những thứ như thế là tầm thường trong C++ với các khuôn mẫu, nhưng, tất nhiên, tôi không bắt đầu một đối số ngu ngốc và vô nghĩa nào về những gì tốt hơn .NET Generics hoặc C++ templates. Xin vui lòng, bỏ qua câu cuối cùng này.
EDIT4
Nhờ https://stackoverflow.com/users/267/lasse-v-karlsen đã cung cấp câu trả lời. Thực ra, tôi đã sử dụng mẫu mã của mình để viết một lớp đơn giản như thế này:
public static class Utils<T>
{
private static class ToDoubleConverterHolder
{
internal static Func<T, double> Value = EmitConverter();
private static Func<T, double> EmitConverter()
{
ThrowIfNotConvertableToDouble(typeof(T));
var method = new DynamicMethod(string.Empty, typeof(double), TypeArray<T>.Value);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
if (typeof(T) != typeof(double))
{
il.Emit(OpCodes.Conv_R8);
}
il.Emit(OpCodes.Ret);
return (Func<T, double>)method.CreateDelegate(typeof(Func<T, double>));
}
}
public static double ConvertToDouble(T value)
{
return ToDoubleConverterHolder.Value(value);
}
}
đâu:
- ThrowIfNotConvertableToDouble (Type) là một phương pháp đơn giản mà làm cho chắc chắn rằng loại nhất định có thể được chuyển đổi sang gấp đôi , tức là một số kiểu số hoặc bool.
- TypeArray là một lớp helper để sản xuất
new[]{ typeof(T) }
Phương pháp Utils.ConvertToDouble chuyển đổi bất kỳ giá trị số tăng gấp đôi trong cách hiệu quả nhất, thể hiện bởi câu trả lời cho câu hỏi này.
Nó hoạt động như một người quyến rũ - cảm ơn người đàn ông.
Vấn đề với trên cũng là nó không có ý nghĩa nhiều. Tại sao sử dụng một phương pháp chung, với một ràng buộc, và sau đó cứng đúc nó đến một đôi? Bạn có thể giải thích rõ hơn những gì bạn đang cố gắng đạt được không? –
Điều này thật lạ lùng với tôi. Tại sao bạn đúc một cấu trúc chung cho một đối tượng và sau đó đến một đôi? Có vấn đề gì với ví dụ này không? Chúng ta có cần thêm ngữ cảnh không? Mã này có vẻ như vậy, tôi không biết cách trả lời ... –
Tôi đã cập nhật câu hỏi. – mark