在.NET对象上设置“空”属性 - c#

我有一些.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;

mscorlib_TLB单元来自Project JEDI中的JCL,在这里:

https://github.com/project-jedi/jcl/blob/master/jcl/source/windows/mscorlib_TLB.pas

在TDotNetObject.SetProperty中调用LPropertyInfo.SetValue时引发错误:

Project TestProject.exe raised exception class EOleException with message 'Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[MTData.Transport.Tracking.DefectReporting.DefectStatus]''.

C#对象上的DefectStatus属性声明为:

public DefectStatus? Status

(即它可以为空)

C#中的Status属性类型声明为:

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
}

我在这里找到了如何使用C#处理这种情况的解决方案:

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

但是我对如何在Delphi中执行相同操作感到迷茫。有任何想法吗?

编辑

鉴于奥利维尔的回答,我试图编写一些Delphi代码来做等效的操作,如下所示:

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;

这段代码的目标只是调用Enum类型的ToObject方法。成功获取LType和LDefectStatusType,但是对InvokeMember_2的调用未成功,返回码为:0x80131512,这显然是Missing Member异常。关于我在做什么错的任何想法吗?

参考方案

问题在于枚举不是int,这意味着SetValue()需要执行两次转换(Int32DefectStatusDefectStatusDefectStatus?),而不能(只能执行一个) )。

这是一个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

在.Net Core 2.0中使用会话 - c#

我正在将一个较旧的小型mvc5应用程序移植到.Net Core 2.0和MVC 6,更多地是作为练习来学习如何做。在该应用程序中,我有一个Base Controller类,其主要工作是确保布局模型中包含用户的配置文件对象。 protected override void OnActionExecuted(ActionExecutedContext filte…

在.NET中导入模块,然后将其用作对象? - c#

                                我有一个Python模块,我希望能够像C#中的类一样导入它的一部分,并尽可能地访问其方法,例如.NET native。如何使用IronPython完成此操作? 参考方案 看一下这个:https://wiki.python.org/moin/IntegratingPythonWithOtherLa…

在.NET和Python中\ Q \ E是否等效? - c#

PHP && Java正则表达式可让您像这样在\Q和\E之间转义部分正则表达式\d+\Q**(+)**\E\d+ 例如12**(+)**22的此匹配项这很方便,因为没有它,您就必须逃脱特殊字符\d+\*\*\(\+\)\*\*\d+ .NET中有类似的东西吗?关于Python也有同样的问题谢谢 参考方案 Python不支持\Q \E。您可以使…

解决编译器错误CS1519:类,结构或接口成员声明中的无效令牌',' - c#

我正在使用Web应用程序项目文件的ASP .NET 2.0站点上工作,因此可以编译为dll,而不是像处理较旧样式的Web站点项目一样部署源代码。该站点在网站的根目录中运行时,在我的测试服务器(Windows Server 2003 R2,IIS6)上可以正常运行。但是,我需要在虚拟目录下运行它。切换到该页面时,浏览到站点中的任何页面时都会收到以下错误CS15…

将字符串分配给numpy.zeros数组[重复] - python

This question already has answers here: Weird behaviour initializing a numpy array of string data                                                                    (4个答案)         …