2017-07-06 14 views
10

Vì vậy, tôi có đoạn mã sau trong C#:C# chức năng sử dụng chức năng mở rộng nhưng VB tương đương không?

public Container ConfigureSimpleInjector(IAppBuilder app) 
{ 
    var container = new Container(); 

    container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle(); 

    container.RegisterPackages(); 

    app.Use(async (context, next) => 
    { 
     using (AsyncScopedLifestyle.BeginScope(container)) 
     { 
      await next(); 
     } 
    }); 

    container.Verify(); 

    return container; 
} 

Các app.Use() được định nghĩa là Owin.AppBuilderUserExtensions.Use() và trông như thế này:

public static IAppBuilder Use(this IAppBuilder app, Func<IOwinContext, Func<Task>, Task> handler);

VB tương đương như sau:

Public Function ConfigureSimpleInjector(app As IAppBuilder) As Container 
    Dim container = New Container() 

    container.Options.DefaultScopedLifestyle = New AsyncScopedLifestyle() 

    container.RegisterPackages() 

    app.Use(Async Sub(context, [next]) 
       Using AsyncScopedLifestyle.BeginScope(container) 
        Await [next]() 
       End Using 
      End Sub) 

    container.Verify() 

    Return container 
End Function 

Vì một số lý do, trong phiên bản VB, app.Use() không sử dụng chức năng mở rộng đó là có sẵn và chỉ cần sử dụng IAppBuilder.Use() thay vào đó, như sau:

Function Use(middleware As Object, ParamArray args() As Object) As IAppBuilder

Tại sao mã VB không sử dụng chức năng mở rộng giống như C# làm và làm thế nào tôi có thể làm cho nó sử dụng ?

Chỉnh sửa

Để rõ ràng, các phương pháp mở rộng không phải là của riêng tôi. Họ đến từ thư viện của Owin 3rd. Vì vậy, không có tùy chọn đổi tên các phương thức mở rộng.

+1

Sẽ tạo sự khác biệt nếu bạn sử dụng 'Func' thay cho' Sub' trong 'app.Use (Async ...'? – pasty

+0

Tôi tin rằng không, bởi vì theo như tôi biết, nó không phải trả lại một giá trị. Tôi có nghĩa là sử dụng 'Chức năng' thay vì ném một lỗi, bởi vì sau đó của nó –

+2

IMO nó nên.Để sử dụng một phương pháp overriden, chữ ký phải phù hợp. Hãy xem [định nghĩa] (https://msdn.microsoft.com/en-us/library/owin. appbuilderuseextensions.use (v = vs.113) .aspx? cs-save-lang = 1 & cs-lang = vb # code-snippet-1) Nếu không, trình biên dịch biết, bạn muốn gọi chính xác phương thức này như thế nào? Hiện tại Sub nó được xem như một tham số (và do đó định nghĩa phương thức đầu tiên được sử dụng). Làm thế nào để bạn bây giờ (bạn có thể xác minh) trong phiên bản C#, nó gọi phương thức với tham số Func? – pasty

Trả lời

4

Trong VB (fiddle), bạn có thể vượt qua một biểu thức lambda khi một đối tượng được yêu cầu:

Public Shared Sub Main() 
    MyMethod(Function() True) ' compiles 
End Sub 

Public Shared Sub MyMethod(o As Object) 
End Sub 

Trong C# (fiddle), điều đó không làm việc:

public static void Main() 
{ 
    // Compilation error: Cannot convert lambda expression to type 'object' because it is not a delegate type. 
    // You'd need to use: MyMethod(new Func<bool>(() => true)); 
    MyMethod(() => true); 
} 

public static void MyMethod(object o) { } 

Đây là có thể do thực tế là các biểu thức lambda có thể được chuyển đổi hoàn toàn thành các đại biểu trong VB but not in C#:

' Compiles 
Dim d As System.Delegate = Function() True 
// Compilation error: Cannot convert lambda expression to type 'Delegate' because it is not a delegate type 
System.Delegate d =() => true; 

Vì vậy, trong ví dụ mã của bạn, VB tìm phương thức thể hiện phù hợp phù hợp và sử dụng nó. Trong mã C#, không tìm thấy phương thức ví dụ phù hợp (vì biểu thức lambda của bạn không khớp với object) và phương thức tiện ích mở rộng được sử dụng thay thế.

Lưu ý rằng cả hai ngôn ngữ thích các phương pháp thể hiện qua các phương pháp mở rộng nếu tìm thấy phương thức phù hợp. Điều này can lead to subtle bugs nếu một phương pháp ví dụ phù hợp được thêm vào sau này.


Cách khắc phục điều đó?Tôi đề nghị sử dụng các tên khác nhau cho phương thức mở rộng và phương thức cá thể - các nhà phát triển khác đọc mã của bạn trong tương lai sẽ cảm ơn bạn vì nó. Nếu đó không phải là một tùy chọn, bạn luôn có thể gọi phương thức tiện ích một cách rõ ràng:

Owin.AppBuilderUserExtensions.Use(app, Async Sub(context, [next]) ...) 
+1

Cảm ơn bạn đã chỉnh sửa câu trả lời của tôi (giờ đã bị xóa). Tôi nghĩ bạn đã có ý tưởng đúng ở đây. Một biểu thức lambda dường như không được chuyển đổi hoàn toàn thành 'đối tượng' trong C#. Nó có thể có giá trị thêm rằng một 'Func' * là * ngầm chuyển đổi, nhưng tất nhiên một biểu thức lambda không phải là một' Func'. Trong ví dụ của bạn, Nếu bạn đã thay thế 'MyMethod (() => true)' bằng 'MyMethod (new Func (() => true))', thì nó sẽ biên dịch và nó sẽ thích một 'MyMethod' cấp độ thể hiện cho một phương thức mở rộng ngay cả khi phần mở rộng đã lấy một 'Func ' thay vì một 'đối tượng'. –

+0

@JoeFarrell: Chính xác. Tôi nghĩ rằng đó là do thực tế là lambdas có thể được chuyển đổi hoàn toàn cho các đại biểu trong VB nhưng không phải trong C#. Tôi đã thêm một ví dụ ngắn vào câu trả lời của tôi. – Heinzi

+0

Các phương pháp mở rộng là từ thư viện của bên thứ ba Owin. Vì vậy, rõ ràng đổi tên mọi thứ không phải là một lựa chọn. Làm thế nào tôi sẽ gọi phương thức mở rộng một cách rõ ràng? Tôi không thể làm 'IAppBuilder.Use (...)' –

5

Trong mã C# vì next là Func và awaitreturns a task, không có báo cáo trả lại nhưng thực tế đối tượng Task được trả lại.

IMO mã VB.NET không trả về một đối tượng Task, vì lambda được quy định như Sub (= Action trong C#).

Thay đổi Sub thành Func trong mã VB.NET nên gọi phương thức mong muốn.

+1

@JunKang: Hãy thử điều này sau đó: 'Chức năng Async (bối cảnh Như IOwinContext, [tiếp theo] Là Func (Nhiệm vụ)) Nhiệm vụ' –

+1

Bạn có thể thử thay vì sử dụng lambda, để tạo ra một chức năng riêng với chữ ký phù hợp và vượt qua nó như một tham số. – pasty

+0

Đề xuất cuối cùng mà tôi có thể nghĩ đến ... Điều gì về cách thức rất rõ ràng này: 'app.Use (New Func (của IOwinContext, Func (Of Task), Task) (Chức năng Async (context Như IOwinContext, [next] As Func (Nhiệm vụ)) Là nhiệm vụ ... mã của bạn ...)) '? –

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