2012-05-16 30 views
12

Dự án tôi sử dụng chứa rất nhiều lớp được kế thừa từ một lớp cơ sở duy nhất. Trong các bài kiểm tra đơn vị tôi cần so sánh kết quả nhận được theo loại và dữ liệu.Trình biên dịch F # ném OutOfMemoryException

Khi tôi sử dụng đối sánh so sánh theo loại trong trường hợp khi danh sách điều kiện chứa đủ trình điều khiển khác nhau đủ ném OutOfMemoryException.

Ví dụ, sau F # mã tăng System.OutOfMemoryException (lỗi thông số FS0193) trong quá trình biên soạn (và biên soạn mất khoảng 30 giây trước khi ngoại lệ được ném)

type IBaseClass() = class end 

type IChildClass1() = inherit IBaseClass() 

type IChildClass2() = inherit IBaseClass() 

type IChildClass3() = inherit IBaseClass() 

type IChildClass4() = inherit IBaseClass() 

type IChildClass5() = inherit IBaseClass() 

type IChildClass6() = inherit IBaseClass() 

type IChildClass7() = inherit IBaseClass() 

type IChildClass8() = inherit IBaseClass() 

type IChildClass9() = inherit IBaseClass() 

type IChildClass10() = inherit IBaseClass() 

type IChildClass11() = inherit IBaseClass() 

type IChildClass12() = inherit IBaseClass() 

type IChildClass13() = inherit IBaseClass() 

type IChildClass14() = inherit IBaseClass() 

type IChildClass15() = inherit IBaseClass() 

type IChildClass16() = inherit IBaseClass() 

type IChildClass17() = inherit IBaseClass() 

type IChildClass18() = inherit IBaseClass() 

type IChildClass19() = inherit IBaseClass() 

type IChildClass20() = inherit IBaseClass() 


let AreEqual (original: IBaseClass) (compareWith: IBaseClass) : bool = 
    match (original, compareWith) with 
    | (:? IChildClass1 as a), (:? IChildClass1 as b) -> a = b 
    | (:? IChildClass2 as a), (:? IChildClass2 as b) -> a = b 
    | (:? IChildClass3 as a), (:? IChildClass3 as b) -> a = b 
    | (:? IChildClass4 as a), (:? IChildClass4 as b) -> a = b 
    | (:? IChildClass5 as a), (:? IChildClass5 as b) -> a = b 
    | (:? IChildClass6 as a), (:? IChildClass6 as b) -> a = b 
    | (:? IChildClass7 as a), (:? IChildClass7 as b) -> a = b 
    | (:? IChildClass8 as a), (:? IChildClass8 as b) -> a = b 
    | (:? IChildClass9 as a), (:? IChildClass9 as b) -> a = b 
    | (:? IChildClass10 as a), (:? IChildClass10 as b) -> a = b 
    | (:? IChildClass11 as a), (:? IChildClass11 as b) -> a = b 
    | (:? IChildClass12 as a), (:? IChildClass12 as b) -> a = b 
    | (:? IChildClass13 as a), (:? IChildClass13 as b) -> a = b 
    | (:? IChildClass14 as a), (:? IChildClass14 as b) -> a = b 
    | (:? IChildClass15 as a), (:? IChildClass15 as b) -> a = b 
    | (:? IChildClass16 as a), (:? IChildClass16 as b) -> a = b 
    | (:? IChildClass17 as a), (:? IChildClass17 as b) -> a = b 
    | (:? IChildClass18 as a), (:? IChildClass18 as b) -> a = b 
    | (:? IChildClass19 as a), (:? IChildClass19 as b) -> a = b 
    | (:? IChildClass20 as a), (:? IChildClass20 as b) -> a = b 
    | _ -> false 

Chắc chắn tôi có thể thêm giao diện IEquatable để lớp học của tôi IBaseClass đó là sẽ tránh được sử dụng như trận đấu xây dựng, hoặc thêm int Kind thành viên (hoặc enum) để giao diện IBaseClass và làm trận đấu không theo loại, nhưng do một số int giá trị.

Lưu ý, tôi đã cố gắng để biên dịch các dự án tương tự trong MS VS 2010 và MSVS 11 Beta, và có cùng một lỗi biên dịch

Câu hỏi: Tại sao OutOfMemoryException của trình biên dịch sẽ xảy ra trong trường hợp của tôi (là nó biết trình biên dịch lỗi hoặc giới hạn khác), tôi nên tổ chức lại điều kiện phù hợp với điều kiện của mình để tránh điều đó như thế nào?

Cập nhật Khi tôi đặt lớp học vào các đoàn thể phân biệt và sử dụng tương tự trận đấu so Fsc.exe biên dịch dự án không có ngoại lệ

type AllClasses = 
    | ChildClass1 of IChildClass1 | ChildClass2 of IChildClass2 | ChildClass3 of IChildClass3 | ChildClass4 of IChildClass4 | ChildClass5 of IChildClass5 | ChildClass6 of IChildClass6 
    | ChildClass7 of IChildClass7 | ChildClass8 of IChildClass8 | ChildClass9 of IChildClass9 | ChildClass10 of IChildClass10 | ChildClass11 of IChildClass11 | ChildClass12 of IChildClass12 
    | ChildClass13 of IChildClass13 | ChildClass14 of IChildClass14 | ChildClass15 of IChildClass15 | ChildClass16 of IChildClass16 | ChildClass17 of IChildClass17 | ChildClass18 of IChildClass18 
    | ChildClass19 of IChildClass19 | ChildClass20 of IChildClass20 

let AreEqual2 (original: AllClasses) (compareWith: AllClasses) : bool = 
    match (original, compareWith) with 
    | ChildClass1(a), ChildClass1(b) -> a = b 
    | ChildClass2(a), ChildClass2(b) -> a = b 
    | ChildClass3(a), ChildClass3(b) -> a = b 
    | ChildClass4(a), ChildClass4(b) -> a = b 
    | ChildClass5(a), ChildClass5(b) -> a = b 
    | ChildClass6(a), ChildClass6(b) -> a = b 
    | ChildClass7(a), ChildClass7(b) -> a = b 
    | ChildClass8(a), ChildClass8(b) -> a = b 
    | ChildClass9(a), ChildClass9(b) -> a = b 
    | ChildClass10(a), ChildClass10(b) -> a = b 
    | ChildClass11(a), ChildClass11(b) -> a = b 
    | ChildClass12(a), ChildClass12(b) -> a = b 
    | ChildClass13(a), ChildClass13(b) -> a = b 
    | ChildClass14(a), ChildClass14(b) -> a = b 
    | ChildClass15(a), ChildClass15(b) -> a = b 
    | ChildClass16(a), ChildClass16(b) -> a = b 
    | ChildClass17(a), ChildClass17(b) -> a = b 
    | ChildClass18(a), ChildClass18(b) -> a = b 
    | ChildClass19(a), ChildClass19(b) -> a = b 
    | ChildClass20(a), ChildClass20(b) -> a = b 
    | _ -> false 

Cảm ơn

+0

Tôi giả sử bạn đang sử dụng 'IChildClass1-20' chỉ cho mục đích minh họa hoặc là mã thực tế này? Tôi không nghĩ bản thân trình biên dịch nên ném một 'OutOfMemoryException' (nhưng tôi không có câu trả lời) – Abel

+0

@Abel - vâng, tên lớp chỉ dành cho mục đích minh họa, các lớp chắc chắn có các tên khác nhau. Lưu ý trên máy tính của tôi nếu tôi sử dụng IChildClass1-18 trong * AreEqual * - dự án là compilable, 19 và nhiều hơn nữa - bùng nổ ...ngoại lệ – Vitaliy

Trả lời

9

này là do cách F # biên dịch biên dịch khớp mẫu trên các bộ dữ liệu trong trường hợp này. Tôi không hoàn toàn chắc chắn khi chính xác bạn chạy trong vấn đề này cụ thể và khi trình biên dịch sử dụng cách tiếp cận khác, nhưng đây là một lời giải thích tại sao nó không thành công ...

Nếu bạn viết mẫu phù hợp ví dụ của bạn, trình biên dịch cơ bản tạo ra cây quyết định kiểm tra mẫu đầu tiên cho original (:? IChildClass1) và sau đó tạo ra hai nhánh. Chi nhánh đầu tiên kiểm tra xem compareWith cũng có phải là IChildClass1 hay không. Nếu có, nó sẽ chạy trường hợp đầu tiên. Phần còn lại của mô hình kết hợp là sau đó nhân đôi ở cả hai chi nhánh, vì vậy bạn sẽ có được một cái gì đó tương tự (bạn có thể kiểm tra điều này bằng cách nhìn vào mã biên dịch cho số nhỏ các trường hợp sử dụng ILSpy):

if (original is IChildClass1) 
    if (compareWith is IChildClass1) 
    case #1 
    if (original is IChildClass2) 
    if (compareWith is IChildClass2) 
     case #2 
    if (original is IChildClass3) 
     (...) 
else 
    if (original is IChildClass2) 
    if (compareWith is IChildClass2) 
     case #2 
    if (original is IChildClass3) 
     (...) 

này có nghĩa là kích thước của mã được tạo ra là tỷ lệ theo cấp số nhân với số lượng các trường hợp trong mẫu phù hợp này. Trong 20 trường hợp, trình biên dịch cố gắng tạo ra 2^20 nhánh, điều này (không ngạc nhiên) thất bại.

+0

cảm ơn bạn đã giải thích. có, tôi hiểu rằng Fsc tạo ra 2^20 chi nhánh, điều gì gây ra ngoại lệ. Nhưng nếu tôi đặt giao diện vào các công đoàn phân biệt (loại AllClasses = ChildClass1 của IChildClass1 | ChildClass2 của IChildClass2 | ChildClass3 của IChildClass3 ...) và sử dụng cùng một * match * bởi tuples với các công đoàn phân biệt - trình biên dịch biên dịch dự án mà không có vấn đề - vì vậy có vẻ như giống như vì một số lý do được biên dịch khác nhau nếu - các nhánh khác để so sánh theo loại và so sánh với các công đoàn phân biệt – Vitaliy

+1

@Vitaliy Như tôi đã nói - tôi không biết chính xác trình biên dịch quyết định phải làm gì. Tuy nhiên, việc biên dịch các công đoàn bị phân biệt đối xử hoàn toàn khác với việc kiểm tra các giao diện. Trong trường hợp DU, trình biên dịch biết rằng chỉ có một trường hợp sẽ giữ. Trong trường hợp giao diện, giá trị có thể khớp với nhiều mẫu (nó có thể triển khai nhiều giao diện). –

+1

LOL. Tôi đã có cùng một lỗi trong HLVM. http://flyingfrogblog.blogspot.co.uk/2010/04/variant-types-and-pattern-matching-in.html –

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