Câu hỏi C #: Func <> thay vì các phương thức? [bản sao]


Câu hỏi này đã có câu trả lời ở đây:

  • Func Delegate vs Hàm                     6 câu trả lời                 

Đây là một câu hỏi tò mò cho tất cả các bạn biết:

Có bất kỳ tác hại / nhược điểm nào khi sử dụng Func thay vì phương thức không? Ví dụ đơn giản:

private static Func<int, int, DBContext, List<T>> Foo =
    (i1, i2, dbc) =>
        (i1 != 0) ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };

Vs

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    return i1 != 0 ? dbc.Bar(i2) : new List<T> { /*some default values ...*/ };
}

13
2017-08-24 07:40


gốc


IMO câu hỏi đầu tiên nên được lợi thế của việc làm như vậy là gì? - Brian Rasmussen
Như những người khác đã chỉ ra: Tại sao bạn sẽ làm điều đó? - Daniel Hilgarth


Các câu trả lời:


Tôi thấy những nhược điểm nghiêm trọng:

  • tác động hiệu suất (đại biểu vs phương pháp) - nhỏ nhưng nó có
  • không có tên tham số (làm tổn thương khả năng đọc trên các cuộc gọi)
  • bản thân định nghĩa ít dễ đọc hơn
  • không thể quá tải (nhờ xanatos)

khi bạn đạt được không có gì tôi sẽ chỉ như vậy trong một bối cảnh địa phương và nhỏ và thích phương pháp tĩnh


10
2017-08-24 07:45



Tác động hiệu suất của delegate vs static method là đáng kể! - MattDavey
ok - có lẽ nhỏ là tương đối;) - Carsten
Tôi sẽ thêm: không thể quá tải. - xanatos
có tất cả các cuộc gọi phương thức tĩnh, gọi lại là các cuộc gọi phương thức nhanh nhất mà bạn có thể thực hiện trong C # - các đại biểu là chậm nhất :) - MattDavey
tôi đôi khi sử dụng hàm cung cấp danh sách chứ không phải chính danh sách trong ngữ cảnh nơi dữ liệu cập nhật là rất quan trọng. Một danh sách từ một nguồn cơ sở dữ liệu là cũ ngay khi nó được tạo ra. Một hàm có thể (re) lấy nó chính xác khi cần thiết. Vì vậy, trong trường hợp này có một lợi ích rõ ràng. - Gert Arnold


Hiệu suất không nhiều như một đối số vì nó có vẻ như ban đầu, chi phí gọi một đại biểu và một phương thức được gửi đi thông qua v_table (các phương thức cá thể ảo) có thể so sánh được. Trong trường hợp này, đối với một phương thức tĩnh, có khả năng có một hiệu suất nhỏ cho việc không sử dụng ủy nhiệm.

"Bí quyết" mà bạn phát hiện ra ở đây là một kỹ thuật khá phổ biến để đạt được phân tích chức năng mà không cần đến kỹ thuật lập trình hướng đối tượng (ví dụ: Mẫu chiến lược). Bạn thay thế một cuộc gọi phương thức bằng một cuộc gọi đến một đại biểu. Một khía cạnh khác của mẹo này là cú pháp cho lời gọi là giống nhau.

Tuy nhiên, tôi sẽ cực kỳ cẩn thận khi áp dụng kỹ thuật này. Những gì tôi thường sử dụng nó cho là để tránh giao diện với một phương pháp duy nhất, mà không có nhiều hơn một hoặc hai tham số (khác tôi sẽ xem xét việc sử dụng một đối tượng tham số hoặc sử dụng một giao diện).

C # là một ngôn ngữ đa mô hình, và sử dụng mỗi mô hình có vị trí của nó. Các mô hình chức năng (chẳng hạn như sử dụng Func thay vì các phương thức biên dịch đã biết) có vị trí của chúng, cũng như các mô hình hướng đối tượng. Trong trường hợp của bạn, không có lợi ích gì khi sử dụng Func<>thay vào đó, bạn nên sử dụng phương pháp truyền thống để làm rõ.


5
2017-08-24 07:54



+1! đẹp - "Bí quyết" bạn phát hiện ở đây là một kỹ thuật khá phổ biến để đạt được phân tích chức năng mà không cần đến kỹ thuật lập trình hướng đối tượng (ví dụ: Mẫu chiến lược). - l--''''''---------''''''''''''


Trong trường hợp đầu tiên (với Func), bạn không viết một phương thức, mà là một biến Foo mà bạn khởi tạo với một đại biểu cụ thể. Bạn có một mức độ gián tiếp mà bạn có thể sử dụng để thay đổi những gì Foo trỏ đến. Để đơn giản hóa ví dụ của bạn:

public static class Test {

    public static Func<int, int, int> Foo =
        (i1, i2) =>
            i1 + i2;

    public static int Foo2(int i1, int i2)
    {
        return i1 + i2;
    }
}

hãy kiểm tra:

int a = Test.Foo(2,3);
int b = Test.Foo2(2,3);

Console.WriteLine("{0}, {1}",a,b); // 5, 5, all seems good, they're both sums

    //... but wait... now you can do this:
Test.Foo = (x,y) => x * y; //reassigning Foo
int c = Test.Foo(2,3);
Console.WriteLine("{0}",c); // 6 

vì vậy, nếu bạn đang sử dụng cấp độ này, thì cách tiếp cận Func có ý nghĩa. Nhưng nếu bạn không sử dụng nó, bạn đã giới thiệu một mức độ quá nhiều, với tác động đến hiệu suất, về cách mã của bạn truyền đạt ý định của nó và đúng đắn cho chương trình của bạn (vì phương pháp của bạn bây giờ có thể được chuyển sang có gì khác khi chạy)


4
2017-08-24 08:01



Đây là câu trả lời chính xác. Đây là một kỹ thuật hợp lệ để sử dụng trong trường hợp bạn muốn gán cho Foo. - Brian B


lý tưởng bạn sẽ không muốn tạo một Func nếu có chỉ là một định nghĩa của nó luôn luôn .. bạn đang không cần thiết làm tăng sự phức tạp và dễ đọc của mã và do đó ảnh hưởng đến khả năng bảo trì ..

nếu bạn có lý do chính đáng để sử dụng nó như bạn tạo Func động dựa trên các điều kiện nhất định sau đó sử dụng Func <> là hợp lý ..

Ngoài ra hãy xem Hành động. đây là một blog mà tôi đọc để giải thích khi nào nên sử dụng cái gì: http://simpleprogrammer.com/2010/09/24/explaining-what-action-and-func-are/


2
2017-08-24 07:48



Hành động không phù hợp trong trường hợp này khi đại biểu của mình cần trả về một giá trị - MattDavey
đã thay đổi nó rồi .. đã nhận ra nó sau - Baz1nga


Từ quan điểm "cuốn sách học tập" nó phải giống nhau, nhưng

  • tác động hiệu suất nhỏ, bởi vì lambdas / đại biểu chậm hơn một chút so với các phương pháp
  • các tham số có tên chung (ví dụ: arg1, arg2)
  • Intellisense thường không thể cung cấp chú giải công cụ tài liệu
  • Các phương thức được định nghĩa là các trường lambda không thể đưa ra các tham số chung mới
  • tác động đọc được

2
2017-08-24 07:55





Ngoài việc hạ cấp có thể đọc được, tôi không nghĩ có bất kỳ tác hại nào khác. Bạn không chắc về cách mã biên dịch, nhưng trên phiên bản đầu tiên bạn chỉ định nghĩa hàm bằng cách sử dụng một ủy nhiệm. Tôi cho rằng bạn cũng có thể làm như sau:

private static List<T> Foo(int i1, int i2, DBContext dbc)
{
    i1 != 0 ? return dbc.Bar(i2) : return new List<T> { /*some default values ...*/ };
}

private static Func<int, int, DBContext, List<T>> Foo2 = Foo;

1
2017-08-24 07:45