2009-07-24 40 views
5

Trong C#, làm thế nào để tạo một loại đại biểu ánh xạ các loại đại biểu cho một loại đại biểu? Cụ thể, trong ví dụ dưới đây, tôi muốn khai báo một đại biểu Sum sao cho (vay từ ký hiệu toán học) Sum(f,g) = f + g. Sau đó tôi muốn gọi Sum(f,g) - chẳng hạn như Sum(f,g)(5) [ý nghĩa này f(5) + g(5)].C#: cách tạo loại đại biểu từ các loại đại biểu?

class Example 
{ 
delegate int IntToInt (int i) ; 

public static int Double (int i) { return i * 2 ; } 
public static int Square (int i) { return i * i ; } 

delegate IntToInt IntToIntPair_To_IntToInt (IntToInt f, IntToInt g) ; 

public static IntToInt Sum (IntToInt f, IntToInt, g) { return f + g ; } 

public static void Main () 
    { 
    IntToInt DoubleInstance = Double ; 
    IntToInt SquareInstance = Square ; 

    IntToIntPair_To_IntToInt SumInstance = Sum ; 

    System.Console.WriteLine 
      (SumInstance (DoubleInstance, SquareInstance) (5)) ; 
    // should print 35 = 10 + 25 = Double(5) + Square(5) 
    } 
} 

Trả lời

14

Bạn chỉ cần thể hiện các loại cụ thể. Ví dụ:

Func<Func<int, int>, Func<int, int>> 

đại diện cho hàm (hàm chuyển đổi int thành int thứ hai) và trả về hàm (chuyển đổi int thành int thứ hai). Hoặc để mất hai chức năng và trả về một thứ ba:

Func<Func<int, int>, Func<int, int>, Func<int, int>> 

Ví dụ:

Func<Func<int, int>, Func<int, int>> applyTwice = (f => x => f(f(x)); 

Điều này có thể được trả lại quát bằng một phương pháp:

public static Func<Func<T,T>, Func<T,T>> ApplyTwice<T>() 
{ 
    return func => x => func(func(x)); 
} 

Nếu bạn muốn tổng hợp hai chức năng , bạn có thể làm:

public static Func<int, int> Sum(Func<int, int> first, Func<int, int> second) 
{ 
    return x => first(x) + second(x); 
} 

Bây giờ để áp dụng nó:

Func<int, int> doubler = x => x * 2; 
Func<int, int> squarer = x => x * x; 
Func<int, int> doublePlusSquare = Sum(doubler, squarer); 

Console.WriteLine(doublePlusSquare(5)); // Prints 35 

(chưa được kiểm tra, nhưng sẽ không sao ...)


Nếu bạn không có C# 3 và .NET 3.5 có sẵn cho bạn, sau đó khai báo các đại biểu sau đây:

public delegate TResult Func<TResult>(); 
public delegate TResult Func<T, TResult>(T arg); 
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); 

(Có thêm về tôi C# Versions page.)

sau đó, bạn sẽ cần phải sử dụng anonymou s phương pháp, ví dụ:

public static Func<int, int> Sum(Func<int, int> first, Func<int, int> second) 
{ 
    return delegate(int x) { return first(x) + second(x); }; 
} 

Func<int, int> doubler = delegate (int x) { return x * 2; }; 
Func<int, int> squarer = delegate (int x) { return x * x; }; 
Func<int, int> doublePlusSquare = Sum(doubler, squarer); 

Console.WriteLine(doublePlusSquare(5)); // Prints 35 
+0

Thiệt tình, bạn nhận được một câu trên một câu trả lời và bam, lại bị xiên. –

+0

Jon: Phần mềm của tôi hơi bị lỗi thời. Có vấn đề gì khi tôi đang sử dụng CLR Version 2.0.50727.42? – JaysonFix

+0

@JaysonFix: Có, thật không may, cú pháp lambda (x => x * 2 chẳng hạn) và các loại đại biểu Func là cấu trúc C# 3/.NET3.5. Để làm điều này trong .NET2.0 và C# 2 sẽ mất nhiều công sức hơn. –

0

Giống như Jon nói:

Func<int, int> f = i => i * 2; 
Func<int, int> g = i => i * i; 
Func<int, int> sum = i => f(i) + g(i); 

Tuy nhiên, nếu bạn muốn tạo ra một phương pháp Sum với nhiều loại khác hơn Func < int, int >, bạn sẽ phải đi với

static Func<T, T> Sum<T>(Func<T, T> f, Func<T, T> g) 
{ 
    ParameterExpression p = Expression.Parameter(typeof(T), "i"); 
    Expression<Func<T, T>> sumExpression = 
      Expression.Lambda<Func<T, T>>(
       Expression.Add(
        Expression.Invoke(Expression.Constant(f), p), 
        Expression.Invoke(Expression.Constant(g), p)), 
       p); 
    return sumExpression.Compile(); 
} 

Điều này phù hợp với mọi loại T xác định toán tử "+". Chỉ cần cẩn thận về hình phạt hiệu suất bạn sẽ nhận được để biên dịch một biểu thức lambda.

+0

Tất nhiên, điều này là dành riêng cho C# 3.0/.NET 3.5. – Ruben

+0

Tôi nghĩ bạn có nghĩa là "các loại khác với int". –

+0

Func thực sự; quên thoát khỏi < >. – Ruben

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