C# 设置一个;“可为空”;.NET对象上的属性

C# 设置一个;“可为空”;.NET对象上的属性,c#,.net,delphi,C#,.net,Delphi,我有一些.NET互操作代码,我已经设法加载对象并读取属性,但是在设置对象的属性时遇到了问题。以下是Delphi代码的相关部分: uses mscorlib_TLB, Winapi.ActiveX; type // Irrelevant parts of the code omitted TDotNetObject = class(TObject) private FTarget: OleVariant; FType: _Type; public pr

我有一些.NET互操作代码,我已经设法加载对象并读取属性,但是在设置对象的属性时遇到了问题。以下是Delphi代码的相关部分:

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;
C#对象上的DefectStatus属性声明为:

public DefectStatus? Status
(即,它可以为空)

声明了C#中的状态属性类型:

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
}

这段代码的目标只是调用枚举类型的ToObject方法。获取LType和LDEECTSTATUSTYPE成功,但是调用InvokeMember_2没有成功,返回代码为:0x80131512,这显然是缺少的成员异常。有没有关于我做错了什么的想法?

问题是枚举不是int,这意味着
SetValue()
需要执行双重转换(
Int32
DefectStatus
DefectStatus
DefectStatus?
),但它不能(它只能执行一次)

下面是一个C#代码,它复制了您试图执行的操作:

using System;
using System.Reflection;

public enum DefectStatus
{
    Reported,
    Assessed,
    OnWorkOrder,
    Closed
}

public class Defect
{
    public DefectStatus? Status {get; set;}
}

public class Test
{
    public static void Main()
    {
        Defect def = new Defect();

        PropertyInfo pi = typeof(Defect).GetProperty("Status");

        // This throws an ArgumentException
//      pi.SetValue(def, 1, null);

        // Retrieve the Assessed enum via its numeric value
        object assessed = Enum.ToObject(typeof(DefectStatus), 1);

        // This works as expected
        pi.SetValue(def, assessed, null);

        Console.WriteLine(def.Status);
    }
}

因此,您需要在Delphi中检索枚举。为此,您需要使用API访问
Enum
类型并在其上调用
ToObject

您是否有可能修改C代码?不幸的是,没有。您如何准确地进行互操作?类
\u Type
\u PropertyInfo
来自哪里?@Olivier他们来自mscorlib\u TLB单元,在这里:可能添加一个
绑定标志\u Public
?谢谢提示。请查看问题中我的编辑
procedure InvokeToObject;
var
  LType, LDefectStatusType: _Type;
  LInvokeFlags: TOleEnum;
  LArgs: PSafeArray;
  LValue: Integer;
  LResult: OleVariant;
  LRes: HRESULT;
  LResHex: string;
begin
  LType := MTDataClr.GetCoreType('System.Enum');
  LDefectStatusType := MTDataClr.GetType('MTData.Transport.Tracking.DefectReporting.DefectStatus');
  LInvokeFlags := BindingFlags_InvokeMethod or BindingFlags_Static;
  LValue := 1;
  LArgs := VariantToPSafeArray(VarArrayOf([LDefectStatusType, LValue]));
  LRes := LType.InvokeMember_2('ToObject', LInvokeFlags, nil, Null, LArgs, nil, LResult);
  LResHex := IntToHex(LRes);
end;
using System;
using System.Reflection;

public enum DefectStatus
{
    Reported,
    Assessed,
    OnWorkOrder,
    Closed
}

public class Defect
{
    public DefectStatus? Status {get; set;}
}

public class Test
{
    public static void Main()
    {
        Defect def = new Defect();

        PropertyInfo pi = typeof(Defect).GetProperty("Status");

        // This throws an ArgumentException
//      pi.SetValue(def, 1, null);

        // Retrieve the Assessed enum via its numeric value
        object assessed = Enum.ToObject(typeof(DefectStatus), 1);

        // This works as expected
        pi.SetValue(def, assessed, null);

        Console.WriteLine(def.Status);
    }
}