C# 设置一个;“可为空”;.NET对象上的属性
我有一些.NET互操作代码,我已经设法加载对象并读取属性,但是在设置对象的属性时遇到了问题。以下是Delphi代码的相关部分: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
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);
}
}