gpt4 book ai didi

c# - 在 .NET 对象上设置 "nullable"属性

转载 作者:行者123 更新时间:2023-12-03 15:34:34 28 4
gpt4 key购买 nike

我有一些 .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 中做同样的事情有点迷失。有什么想法吗?

编辑

鉴于 Olivier 的回答,我尝试编写一些 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() 需要执行双重转换(Int32DefectStatus > 和 DefectStatusDefectStatus?),但它不能(它只能执行一个)。

这是一个 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# - 在 .NET 对象上设置 "nullable"属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61334031/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com