2009-11-23 21 views
5

Tôi đang cố gắng để viết một accessor tài sản lưu trữ chung chung như sau nhưng đang nhận được một lỗi biên dịch khi cố gắng kiểm tra xem biến lưu trữ đã có chứa một giá trị:Làm cách nào để kiểm tra biến kiểu chung cho sự bình đẳng với Mặc định (T) trong Delphi?

function TMyClass.GetProp<T>(var ADataValue: T; const ARetriever: TFunc<T>): T; 
begin 
    if ADataValue = Default(T) then // <-- compiler error on this line 
    ADataValue := ARetriever(); 
    Result := ADataValue; 
end; 

Các lỗi tôi nhận được là " Toán tử E2015 không áp dụng cho loại toán hạng này ".

Tôi có phải đặt một ràng buộc trên T để thực hiện công việc này không? Tệp trợ giúp cho biết rằng Default() sẽ chấp nhận bất kỳ điều gì ngoại trừ các loại chung chung. Trong trường hợp của tôi, tôi chủ yếu giao dịch với các loại đơn giản như String, IntegerTDateTime.

Hoặc có chức năng thư viện nào khác để thực hiện kiểm tra cụ thể này không?

Tôi đang sử dụng Delphi 2009 trong trường hợp có vấn đề.


PS: Chỉ trong trường hợp nó không phải là rõ ràng từ mã những gì tôi đang cố gắng để làm: Trong trường hợp của tôi xác định giá trị tài sản thực tế có thể mất một thời gian vì nhiều lý do và đôi khi tôi có thể thậm chí không cần tất cả. Tuy nhiên, tôi chỉ muốn gọi mã xác định giá trị thực khi lần đầu tiên thuộc tính được truy cập và sau đó lưu trữ giá trị trong trường lớp và lần tiếp theo thuộc tính được truy xuất trả về giá trị được lưu trong bộ nhớ cache trực tiếp. Dưới đây là một ví dụ về cách tôi hy vọng tôi sẽ có thể sử dụng mã rằng:

type 
    TMyClass = class 
    private 
    FSomeProp: String; 
    function GetSomeProp: String; 

    function GetProp<T>(var ADataValue: T; const ARetriever: TFunc<T>): T; 
    public 
    property SomeProp read GetSomeProp; 
    end; 

function GetSomeProp: String; 
begin 
    Result := GetProp<String>(FSomeProp, 
          function: String 
          begin 
           Result := SomeSlowOrExpensiveCalculation; 
          end); 
end; 

(rõ ràng, có nhiều hơn chỉ là một tài sản)

+0

+1 ý tưởng hay bằng cách này. – jpfollenius

+1

Bạn có lẽ nên sử dụng một loại nullable, nếu không mã sẽ liên tục đánh giá lại các thuộc tính đã được lưu trữ nhưng có giá trị mặc định. Xem ví dụ http://blogs.embarcadero.com/abauer/2008/09/18/38869 – mghie

+0

@mghie: Điểm tốt và thông thường tôi sẽ đồng ý nhưng trong trường hợp cụ thể này giá trị mặc định có thể được giải thích một cách an toàn là "chưa được khởi tạo" . –

Trả lời

10

Sau một gợi ý trong các ý kiến ​​từ Binis và đào bới xung quanh một chút trong Generics.Collections tôi đã đưa ra những điều sau đây mà dường như chỉ làm việc như tôi muốn nó :

function TMyClass.GetProp<T>(var ADataValue: T; const ARetriever: TFunc<T>): T; 
var 
    lComparer: IEqualityComparer<T>; 
begin 
    lComparer := TEqualityComparer<T>.Default; 
    if lComparer.Equals(ADataValue, Default(T)) then 
    ADataValue := ARetriever(); 
    Result := ADataValue; 
end; 
+2

Điều đáng chú ý là" IEqualityComparer "hiện nằm trong Generics.Defaults (không chắc chắn từ khi nào, sử dụng Berlin 10.1) – Zulukas

-1

Vấn đề không phải là Default chức năng, nhưng các nhà điều hành bình đẳng = .

Bạn có thể hạn chế T-IEquatable và sử dụng phương pháp Equals như thế này:

TMyClass = class 
    function GetProp<T : IEquatable<T>>(var ADataValue: T; const ARetriever: 
end; 
... 
function TMyClass.GetProp<T>(var ADataValue: T; const ARetriever: TFunc<T>): T; 
begin 
if ADataValue.Equals (Default(T)) then 
    ADataValue := ARetriever(); 
Result := ADataValue; 
end; 
+0

Không chắc chắn tại sao nhưng tôi nhận được một "Số nhận dạng không khai báo" IEquatable '"với mã đó (mặc dù tôi có thể thấy' IEquatable' thực sự được khai báo trong System.pas). Tuy nhiên tôi sẽ nghi ngờ điều này sẽ làm việc cho tôi anyways như tôi không biết rằng các loại nguyên thủy như 'String',' TDateTime' hoặc 'Integer' bằng cách nào đó hoàn toàn hỗ trợ giao diện đó ... –

+0

@Oliver: bạn nói đúng, bạn có thể ' t sử dụng cho các loại nguyên thủy. Thật không may, tôi không nhận thức được một giải pháp khác. Hãy xem liệu những người khác có thể giúp đỡ hay không. Tôi không biết tại sao bạn nhận được thông báo lỗi khi sử dụng 'IEquatable'. – jpfollenius

+0

Trên thực tế, những gì được khai báo trong System.pas không phải là 'IEquatable' nhưng 'IEquatable ' giải thích lỗi ... 'GetProp > (...' không biên dịch nhưng sau đó, như mong đợi, tôi nhận được lỗi khi truyền 'String' cho' T': "Tham số kiểu 'T' phải hỗ trợ giao diện IEquatable " –

1

Như tôi hiểu được những điều có vẻ như u muốn làm một số loại chức năng memoize. Nếu đây là trường hợp chỉ cần đọc bài viết này

http://blogs.teamb.com/craigstuntz/2008/10/01/37839/

+0

Cảm ơn! Điều này thực sự rất giống với những gì tôi đang cố gắng thực hiện nhưng việc thực hiện của Craig sẽ dẫn đến một giá trị không cần thiết lớn trong trường hợp cụ thể của tôi vì nó sẽ khởi tạo một thể hiện 'TDictionary' mới cho mọi thuộc tính ... Thật không may cũng không phải là câu trả lời cho câu hỏi ban đầu về cách kiểm tra xem một biến kiểu chung có giá trị không mặc định hay không hay không, do đó, với bối cảnh đó, tôi e rằng tôi thậm chí không thể đưa ra câu trả lời của bạn. :( –

+0

Bạn có thể tránh được phí tổn này bằng cách sử dụng một cái gì đó như 'TCacheManager'. y. Chỉ cần sử dụng một cái gì đó như 'IntToStr (Integer (Pointer (Self))) + '.Property1'' làm khóa và đăng ký các giá trị được lưu trữ của bạn. – jpfollenius

+3

Cách duy nhất "hợp pháp" để so sánh Generics là làm những gì Delphi làm trong Generics.Collections.pas. Hãy xem triển khai QuickSort. – Binis

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