Jump to content
Sign in to follow this  
Dave Nottage

Setting a "nullable" property on a .NET object

Recommended Posts

I have some .NET interop code where I've managed to load objects and read properties, however I am having trouble with setting a property on an object. Here's the relevant parts of the Delphi code:

uses
  mscorlib_TLB, Winapi.ActiveX;

type
  // Irrelevant parts of the code omitted
  TDotNetObject = class(TObject)
  private
    FTarget: OleVariant;
    FType: _Type;
  public
    procedure SetProperty(const APropertyName: string; const AValue: OleVariant; const AIndex: Integer = -1);
  end;

function VariantToPSafeArray(const AValue: Variant): PSafeArray;
begin
  Result := PSafeArray(VarArrayAsPSafeArray(AValue));
end;

procedure TDotNetObject.SetProperty(const APropertyName: string; const AValue: OleVariant; const AIndex: Integer = -1);
var
  LPropertyInfo: _PropertyInfo;
  LIndex: PSafeArray;
begin
  if AIndex >= 0 then
    LIndex := VariantToPSafeArray(VarArrayOf([AIndex]))
  else
    LIndex := nil;
  LPropertyInfo := FType.GetProperty(APropertyName, BindingFlags_Instance or BindingFlags_Public or BindingFlags_NonPublic);
  if LPropertyInfo <> nil then
    LPropertyInfo.SetValue(FTarget, AValue, LIndex);
end;

procedure UpdateDefectStatus(const ADefectID, AStatus: Integer);
var
  LObject: TDotNetObject;
begin
  // ** Code to obtain the object omitted ***
  LObject.SetProperty('Status', AStatus);
end;

An error is thrown when LPropertyInfo.SetValue is called in TDotNetObject.SetProperty:

 

image.thumb.png.6ba1346f0aaa83cd86f4b7d9204efb2d.png

 

The Status property type in C# is declared:

public enum DefectStatus
{
	/// <summary>
	/// Defect Reported.
	/// </summary>
	Reported,
	/// <summary>
	/// Defect assessed.
	/// </summary>
	Assessed,
	/// <summary>
	/// Defect on work order.
	/// </summary>
	OnWorkOrder,
	/// <summary>
	/// Defect closed.
	/// </summary>
	Closed
}

I found a solution for how to handle this situation using C# here:

https://stackoverflow.com/a/13270302/3164070

However I'm a bit lost as to how to do the same in Delphi. Any ideas?

Share this post


Link to post

100% guesswork without any foundation, except name likeness, follows:

There is a GetUnderlyingType property in System.RTTI type TRttiEnumerationType - but it is used absolutely nowhere in the RTL.
Also, WinAPI.Ole2 contains a VariantChangeType, and WinAPI.ActiveX contains a VariantChangeTypeEx that may be relevant. System.VarUtils contain both.

function TRttiEnumerationType.GetUnderlyingType: TRttiType;
begin
  Result := Pool.TypeOrNil(TypeData^.BaseType);
end;

function TRttiPool.TypeOrNil(Value: PPTypeInfo): TRttiType;
begin
  if Value = nil then
    Exit(nil);
  Result := GetType(Value^);
end;

function TRttiPool.GetType(ATypeInfo: Pointer): TRttiType;
begin
  if ATypeInfo = nil then
    Exit(nil);
  Result := TRttiType(ReadObjectPointer(TRttiType, nil, ATypeInfo));
end;

 

Share this post


Link to post
Guest

The problem, I think, is that .NET's Nullable is a generic type and as such can't be exposed to COM.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×