Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#21

AW: Methoden-Parameter soll Referenz, aber kein nil sein können

  Alt 29. Nov 2013, 11:13
Zwar nicht im Compiler, aber zur Laufzeit sollte es gehen?
Delphi-Quellcode:
type
  TSimpleNonNullable<T> = record
    class operator Implicit(const Value: TSimpleNonNullable<T>): T; inline;
    class operator Implicit(const Value: T): TSimpleNonNullable<T>; inline;
    class procedure Check(const Value: T); inline; static;
  public type
    ENonNullable = class(Exception);
  private
    FValue: T;
  end;

{ TSimpleNonNullable<T> }

class operator TSimpleNonNullable<T>.Implicit(const Value: TSimpleNonNullable<T>): T;
begin
  Check(Value);
  Result := Value.FValue;
end;

class operator TSimpleNonNullable<T>.Implicit(const Value: T): TSimpleNonNullable<T>;
begin
  Check(Value);
  Result.FValue := Value;
end;

class procedure TSimpleNonNullable<T>.Check(const Value: T);
begin
  case SizeOf(Value) of
    4: if PInteger(@Value)^ <> 0 then Exit;
    8: if PInt64(@Value)^ <> 0 then Exit;
    else raise ENonNullable.CreateFmt('TNonNullable<T>: Type %s is not supported.', [GetTypeName(TypeInfo(T))]);
  end;
  raise ENonNullable.CreateFmt('TNonNullable<T>: Variable %s(%p) is null.', [GetTypeName(TypeInfo(T)), @Value]);
end;
Delphi-Quellcode:
uses
  TypInfo, Variants;

type
  TNonNullable<T> = record
    class operator Implicit(const Value: TNonNullable<T>): T; inline;
    class operator Implicit(const Value: T): TNonNullable<T>; inline;
    class procedure Check(const Value: T); static;
  public type
    ENonNullable = class(Exception);
  private
    FValue: T;
  end;

{ TNonNullable<T> }

class procedure TNonNullable<T>.Check(const Value: T);
begin
  case PTypeInfo(TypeInfo(T)).Kind of
    tkPointer, tkClass, tkClassRef, tkInterface, tkProcedure, tkString, tkUString, tkDynArray, tkWString:
      if PPointer(@Value)^ <> nil then
        Exit;
    tkInteger, tkChar, tkWChar, tkEnumeration, tkSet:
      case GetTypeData(TypeInfo(T)).OrdType of
        otSByte, otUByte:
          if PByte(@Value)^ <> 0 then
            Exit;
        otSWord, otUWord:
          if PWord(@Value)^ <> 0 then
            Exit;
        otSLong, otULong:
          if PLongWord(@Value)^ <> 0 then
            Exit;
        else
          raise ENonNullable.CreateFmt('TNonNullable<T>: Type %s is not supported.', [GetTypeName(TypeInfo(T))]);
      end;
    tkInt64:
      if PInt64(@Value)^ <> 0 then
        Exit;
    tkFloat:
      case GetTypeData(TypeInfo(T)).FloatType of
        ftSingle:
          if PSingle(@Value)^ <> 0 then
            Exit;
        ftDouble:
          if PDouble(@Value)^ <> 0 then
            Exit;
        ftExtended:
          if PExtended(@Value)^ <> 0 then
            Exit;
        ftCurr:
          if PCurrency(@Value)^ <> 0 then
            Exit;
        else
          raise ENonNullable.CreateFmt('TNonNullable<T>: Type %s is not supported.', [GetTypeName(TypeInfo(T))]);
      end;
    tkMethod:
      if TMethod(Pointer(@Value)^).Code <> nil then
        Exit;
    tkVariant:
      if not VarIsNull(PVariant(@Value)^) and VarIsEmpty(PVariant(@Value)^) then
        Exit;
    else
      raise ENonNullable.CreateFmt('TNonNullable<T>: Type %s is not supported.', [GetTypeName(TypeInfo(T))]);
  end;

  raise ENonNullable.CreateFmt('TNonNullable<T>: Variable %s(%p) is null.', [GetTypeName(TypeInfo(T)), @Value]);
end;

class operator TNonNullable<T>.Implicit(const Value: TNonNullable<T>): T;
begin
  Check(Value.FValue);
  Result := Value.FValue;
end;

class operator TNonNullable<T>.Implicit(const Value: T): TNonNullable<T>;
begin
  Check(Value);
  Result.FValue := Value;
end;
$2B or not $2B
  Mit Zitat antworten Zitat