2012-07-03 68 views
60

Tôi có một phương pháp chung có yêu cầu và cung cấp phản hồi.void trong C# generics?

public Tres DoSomething<Tres, Treq>(Tres response, Treq request) 
{/*stuff*/} 

Nhưng tôi không luôn luôn muốn trả lời yêu cầu của mình và tôi không luôn muốn cung cấp dữ liệu yêu cầu để nhận phản hồi. Tôi cũng không muốn phải sao chép và dán toàn bộ các phương thức để thực hiện các thay đổi nhỏ. Những gì tôi muốn, là để có thể làm điều này:

public Tre DoSomething<Tres>(Tres response) 
{ 
    return DoSomething<Tres, void>(response, null); 
} 

Điều này có khả thi theo một cách nào đó không? Dường như cụ thể sử dụng void không hoạt động, nhưng tôi hy vọng sẽ tìm thấy một cái gì đó tương tự.

+1

Tại sao không chỉ sử dụng System.Object và làm một kiểm tra null trong DoSomething (Tres response, Treq request)? – James

+0

Lưu ý rằng bạn cần sử dụng giá trị trả về. Bạn có thể gọi các chức năng như thủ tục. 'DoSomething (x);' thay vì 'y = DoSomething (x);' –

Trả lời

61

Bạn không thể sử dụng void, nhưng bạn có thể sử dụng object: đó là một sự bất tiện chút vì sẽ-be- void chức năng bạn cần phải trả lại null, nhưng nếu nó hợp nhất mã của bạn, nó phải là một giá nhỏ để trả tiền.

không có khả năng này sử dụng void như một kiểu trả về ít nhất là một phần trách nhiệm trong một khoảnh khắc giữa Func<...>Action<...> gia đình của các đại biểu chung chung: đã có nó được thể trở void, tất cả Action<X,Y,Z> sẽ trở nên đơn giản Func<X,Y,Z,void>. Thật không may, điều này là không thể.

+26

** (Joke) ** Và anh ta vẫn có thể trả về 'void' từ những phương thức trống rỗng đó, với' return System.Runtime. Serialization.FormatterServices.GetUninitializedObject (typeof (void)); '. Nó sẽ là một khoảng trống đóng hộp, mặc dù. –

1

void, mặc dù loại, chỉ hợp lệ là kiểu trả về của phương thức.

Không có cách nào xung quanh giới hạn này là void.

61

Không, rất tiếc là không. Nếu void là loại "thực" (ví dụ như unit in F#), cuộc sống sẽ đơn giản hơn rất nhiều theo nhiều cách. Đặc biệt, chúng tôi sẽ không cần cả gia đình Func<T>Action<T> - có chỉ muốn được Func<void> thay vì Action, Func<T, void> thay vì Action<T>, vv

Nó cũng sẽ làm cho async đơn giản hơn - thì sẽ không có nhu cầu sử dụng không chung chung loại Task - chúng tôi chỉ có Task<void>.

Thật không may, đó không phải là cách C# hoặc gõ NET hệ thống làm việc ...

+4

'Thật không may, đó không phải là cách mà các hệ thống kiểu C# hoặc .NET hoạt động ...' Bạn đang làm cho tôi hy vọng rằng mọi thứ có thể hoạt động như thế. Điểm cuối cùng của bạn có nghĩa là chúng tôi không có khả năng làm mọi việc theo cách đó? –

+2

@Sahuagin: Tôi nghi ngờ không - nó sẽ là một thay đổi khá lớn vào thời điểm này. –

+0

Liệu có cho phép void như một loại sẽ giống như cho phép null như một tham chiếu? Sai tỷ đô la khác? – stannius

13

Bạn chỉ có thể sử dụng Object như những người khác đã gợi ý. Hoặc Int32 mà tôi đã thấy một số sử dụng. Sử dụng Int32 giới thiệu một số "giả" (sử dụng 0), nhưng ít nhất bạn không thể đặt bất kỳ đối tượng lớn và kỳ lạ vào tham chiếu Int32 (cấu trúc được niêm phong).

Bạn cũng có thể viết bạn sở hữu "khoảng trống" type:

public sealed class MyVoid 
{ 
    MyVoid() 
    { 
    throw new InvalidOperationException("Don't instantiate MyVoid."); 
    } 
} 

MyVoid tài liệu tham khảo được phép (nó không phải là một lớp tĩnh) nhưng chỉ có thể là null. Hàm khởi tạo cá thể là private (và nếu ai đó cố gắng gọi hàm tạo riêng này thông qua sự phản chiếu, một ngoại lệ sẽ được ném vào chúng).

+2

Tên khác cho điều này sẽ là mẫu đối tượng null (mẫu thiết kế). – Aelphaeis

18

Đây là những gì bạn có thể làm. Như @ Johnsonke cho biết không có loại đơn vị trong C#, do đó, làm cho nó cho mình!

public sealed class ThankYou { 
    private ThankYou() { } 
    private readonly static ThankYou bye = new ThankYou(); 
    public static ThankYou Bye { get { return bye; } } 
} 

Bây giờ bạn luôn có thể sử dụng Func<..., ThankYou> thay vì Action<...>

public ThankYou MethodWithNoResult() { 
    /* do things */ 
    return ThankYou.Bye; 
} 

Hoặc sử dụng một cái gì đó đã được thực hiện bởi đội ngũ Rx: http://msdn.microsoft.com/en-us/library/system.reactive.unit%28v=VS.103%29.aspx

+0

System.Reactive.Unit là một gợi ý tốt. Kể từ tháng 11 năm 2016, nếu bạn quan tâm đến việc trở thành một phần nhỏ của khung Hoạt động càng tốt, bởi vì bạn không sử dụng bất kỳ thứ gì khác ngoài lớp Đơn vị, hãy sử dụng trình quản lý gói nuget 'Install-Package System.Reactive.Core' – DannyMeister

1

Tôi thích ý tưởng của Aleksey Bykov trên, nhưng nó có thể được đơn giản hóa một chút

public sealed class Nothing { 
    public static Nothing AtAll { get { return null; } } 
} 

Như tôi không thấy lý do rõ ràng tại sao Nothing.AtAll không thể chỉ cung cấp cho null

Ý tưởng tương tự (hoặc do Jeppe Stig Nielsen) cũng tuyệt vời cho việc sử dụng với các lớp đã nhập.

Ví dụ: nếu loại chỉ được sử dụng để mô tả các đối số cho một thủ tục/hàm được chuyển như một đối số cho một phương thức nào đó, và chính nó không lấy bất kỳ đối số nào.

(Bạn sẽ vẫn cần phải hoặc là làm cho một wrapper giả hoặc cho phép một tùy chọn "Không có gì". Nhưng IMHO việc sử dụng lớp có vẻ tốt đẹp với myClass < Không có gì>)

void myProcWithNoArguments(Nothing Dummy){ 
    myProcWithNoArguments(){ 
} 

hoặc

void myProcWithNoArguments(Nothing Dummy=null){ 
    ... 
} 
+0

Giá trị 'null' có nghĩa là thiếu' đối tượng'. Chỉ có một giá trị cho 'Nothing' có nghĩa là nó không bao giờ trông giống bất cứ thứ gì khác. – LexieHankins