Hàm C # Passing là đối số


141

Tôi đã viết một hàm trong C # để phân biệt số. Nó trông như thế này:

public double Diff(double x)
{
    double h = 0.0000001;

    return (Function(x + h) - Function(x)) / h;
}

Tôi muốn có thể vượt qua trong bất kỳ chức năng nào, như trong:

public double Diff(double x, function f)
{
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

Tôi nghĩ điều này là có thể với các đại biểu (có thể?) Nhưng tôi không chắc cách sử dụng chúng.

Mọi sự trợ giúp sẽ rất được trân trọng.

Câu trả lời:


146

Sử dụng Func như đã đề cập ở trên nhưng cũng có những đại biểu thực hiện cùng một nhiệm vụ và cũng xác định ý định trong việc đặt tên:

public delegate double MyFunction(double x);

public double Diff(double x, MyFunction f)
{
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

public double MyFunctionMethod(double x)
{
    // Can add more complicated logic here
    return x + 10;
}

public void Client()
{
    double result = Diff(1.234, x => x * 456.1234);
    double secondResult = Diff(2.345, MyFunctionMethod);
}

5
Trong 3.5 và sau đó, Func <> s và đại biểu có thể hoán đổi cho nhau và điều đó có nghĩa là các đại biểu ẩn danh và lambdas (là đường cú pháp cho các đại biểu ẩn danh) cũng có thể được sử dụng. Vì vậy, việc bạn chỉ định tham số là Func <double, double> hay đại biểu mất gấp đôi và trả về gấp đôi không quan trọng. Lợi thế thực sự duy nhất mà một đại biểu có tên mang lại cho bạn là khả năng thêm các bình luận xml-doc; Tên mô tả chỉ dễ thực hiện như tên tham số thay vì loại.
KeithS

3
Tôi sẽ lập luận rằng nguyên mẫu phương thức vẫn làm cho mã dễ đọc hơn Func <x, y> - nó không chỉ là cách đặt tên làm cho mã có thể đọc được và như bạn nói điều đó không ngăn bạn chuyển lambdas vào mã.
Ian Johnson

Nếu việc đặt tên loại đại biểu rất quan trọng đối với sự rõ ràng của mã, tôi nghĩ trong hầu hết các trường hợp tôi sẽ nghiêng về một giao diện và triển khai.
quentin-starin

@qstarin nó không chỉ là cách đặt tên của đại biểu mà là cách đặt tên của các đối số mà phương thức phải thực hiện, đặc biệt nếu chúng chỉ là kiểu bản địa. Bạn nói đúng, chủ yếu tôi sử dụng giao diện qua các đại biểu
Ian Johnson

Nếu tôi tạo một trong số này như một chức năng phổ biến cung cấp chức năng chung, (với loại trả về không phổ biến), mọi thứ sẽ hoạt động cho đến khi tôi cố gắng sử dụng nó với khoảng trống. Tôi có thực sự cần phải tạo một chức năng trùng lặp bằng Action thay vì Func hay có cách nào tốt hơn không?
Dan Chase

175

Có một vài loại chung trong .Net (v2 trở lên) giúp chuyển các hàm xung quanh thành đại biểu rất dễ dàng.

Đối với các hàm có kiểu trả về, có Func <> và đối với các hàm không có kiểu trả về thì có Hành động <>.

Cả Func và Action đều có thể được khai báo để lấy từ 0 đến 4 tham số. Ví dụ: Func <double, int> lấy một nhân đôi làm tham số và trả về một int. Hành động <double, double, double> lấy ba nhân đôi làm tham số và không trả về gì (void).

Vì vậy, bạn có thể khai báo hàm Diff của mình để lấy Func:

public double Diff(double x, Func<double, double> f) {
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

Và sau đó bạn gọi nó như vậy, chỉ cần đặt cho nó tên của hàm phù hợp với chữ ký của Func hoặc Action của bạn:

double result = Diff(myValue, Function);

Bạn thậm chí có thể viết hàm thẳng hàng với cú pháp lambda:

double result = Diff(myValue, d => Math.Sqrt(d * 3.14));

29
Trong .NET 4, cả hai FuncActionđã được cập nhật để cho phép tối đa 16 tham số.
Joel Mueller

5
Một điều thực sự thú vị sẽ là trả về một Func<double, double>đạo hàm đầu tiên của hàm đầu vào, tất nhiên được tính bằng số. return x => (f(x + h) - f(x)) / h;Bạn thậm chí có thể viết một quá tải trả về nđạo hàm thứ của hàm đầu vào.
Ani

15
public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Sử dụng:

var ReturnValue = Runner(() => GetUser(99));

Tôi tò mò, tại sao tham số loại chung?
kdbanman

2
Tôi đang gặp lỗi này: Các đối số loại cho phương thức 'Người chạy <T> (Func <T>)' không thể được suy ra từ việc sử dụng. Hãy thử chỉ định rõ ràng các đối số loại.
DermFbler

Chữ ký phương thức "funcToRun" của bạn là gì?
kravits88
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.