【发布时间】:2017-08-19 23:29:31
【问题描述】:
这是一个示例 XML 数据文件:
<?xml version="1.0" encoding="utf-8"?>
<AssignmentHistory Version="171804">
<W20160104>
<StudentItems>
<Item>
<Name Counsel="13" NextCounsel="0" Completed="1">Name 1</Name>
<Type>Bible Reading (Main)</Type>
</Item>
</StudentItems>
</W20160104>
<W20160111>
<StudentItems>
<Item>
<Name Counsel="9" NextCounsel="9" Completed="0">Name 2</Name>
<Type>Bible Reading (Main)</Type>
</Item>
<Item Description="Initial Call">
<Name Counsel="37" NextCounsel="38" Completed="1">Name 1</Name>
<Type>#1 Student (Main)</Type>
</Item>
<Item>
<Name>Name 3</Name>
<Type>Assistant</Type>
</Item>
<Item>
<Name Counsel="48" NextCounsel="49" Completed="1">Name 4</Name>
<Type>#2 Student (Main)</Type>
</Item>
<Item>
<Name>Name 5</Name>
<Type>Assistant</Type>
</Item>
<Item>
<Name Counsel="27" NextCounsel="30" Completed="1">Name 6</Name>
<Type>#3 Student (Main)</Type>
</Item>
<Item>
<Name>Name 7</Name>
<Type>Assistant</Type>
</Item>
</StudentItems>
</W20160111>
</AssignmentHistory>
我编写了一些代码来读取 XML 数据文件并定位给定名称的未来分配历史记录。例如,如果这一周是 2016 年 1 月 4 日,并且我们正在获取名称 1 的历史记录,那么我的代码将返回一个条目列表(在本例中,只有 1 个,表示 2016 年 1 月 11 日这一周)。
我的代码:
我的方法运行良好:
public void ExtractFutureStudentHistory(String strStudent, DateTime datWeekOfMeeting, String strHistoryDatabase, out DateTime[] aryFutureDates, out string[] aryFutureAssignTypes, out int[] aryFutureStudyNo)
{
XmlDocument docAssignHistory = new XmlDocument();
aryFutureDates = null;
aryFutureAssignTypes = null;
aryFutureStudyNo = null;
List<DateTime> listFutureDates = new List<DateTime>();
List<string> listFutureAssignTypes = new List<string>();
List<int> listFutureStudyNo = new List<int>();
try
{
docAssignHistory.Load(strHistoryDatabase);
// The data in the XML should already be in ascending date order
// The data we want:
// AssignmentHistory/<WYYYYMMDD>/StudentItems/Item/Name
// AssignmentHistory/<WYYYYMMDD>/StudentItems/Item/Type
XmlNodeList listHistory = docAssignHistory.SelectNodes("AssignmentHistory/*/StudentItems/Item[Name='" + strStudent + "']");
foreach(XmlNode nodeHistoryItem in listHistory)
{
XmlNode weekNode = nodeHistoryItem.ParentNode.ParentNode;
String strWeekDate = weekNode.Name.Substring(1); // This skips the preceding "W"
DateTime dateHistoryItemWeekOfMeeting = new DateTime(Convert.ToInt32(strWeekDate.Substring(0, 4)),
Convert.ToInt32(strWeekDate.Substring(4, 2)),
Convert.ToInt32(strWeekDate.Substring(6, 2)));
if (dateHistoryItemWeekOfMeeting.Date > datWeekOfMeeting.Date)
{
// We need to include it
listFutureDates.Add(dateHistoryItemWeekOfMeeting);
listFutureStudyNo.Add(Convert.ToInt32(nodeHistoryItem.SelectSingleNode("Name").Attributes["Counsel"].Value));
listFutureAssignTypes.Add(nodeHistoryItem.SelectSingleNode("Type").InnerText);
}
}
aryFutureDates = listFutureDates.ToArray();
aryFutureStudyNo = listFutureStudyNo.ToArray();
aryFutureAssignTypes = listFutureAssignTypes.ToArray();
}
catch (Exception ex)
{
SimpleLog.Log(ex);
}
}
可能逻辑可以简化,但它有效。我的问题在于我的方法是 C# .NET DLL 的一部分。目前我有这个公共接口方法:
[Guid("xx")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IMSAToolsLibraryInterface
{
void ExtractFutureStudentHistory(String strStudent, DateTime datWeekOfMeeting, String strHistoryDatabase, out DateTime[] aryFutureDates, out string[] aryFutureAssignTypes, out Int32[] aryFutureStudyNo);
}
它工作正常。在 C++ MFC 中,我有三个 SAFEARRAY** 对象,一个 BSTR 类型,一个 DATE 类型和一个 int 类型。它本身没问题。
我的问题是,我的函数可以更改为输出单个对象列表吗?例如,如果我创建了一个类:
StudentItem 具有日期、作业类型和研究编号三个成员变量。
我尝试将我的函数参数更改为out List<StudentItem>,但这没有用。然后我把它改成out StudentItem[] 还是不行。
我将StudentItem 声明为具有三个成员的基本struct。声明这个对象的正确方法是什么,以便我可以将它作为数组传回以便在 MFC 中使用?
谢谢。
更新
第 1 步:
我在 DLL 项目中添加了一个新对象:
[Guid("xx")]
[ComVisible(true)]
public struct StudentItem
{
public string Type { get; set; }
public DateTime Week { get; set; }
public int Study { get; set; }
}
第 2 步:
我在界面中添加了一个引用:
void ExtractFutureStudentHistory2(String strStudent, DateTime datWeekOfMeeting, String strHistoryDatabase, out StudentItem[] aryStudentItems);
第 3 步:
我添加调整后的方法:
public void ExtractFutureStudentHistory2(String strStudent, DateTime datWeekOfMeeting, String strHistoryDatabase, out StudentItem[] aryStudentItems)
{
XmlDocument docAssignHistory = new XmlDocument();
aryStudentItems = null;
List<StudentItem> listStudentItems = new List<StudentItem>();
try
{
docAssignHistory.Load(strHistoryDatabase);
// The data in the XML should already be in ascending date order
// The data we want:
// AssignmentHistory/<WYYYYMMDD>/StudentItems/Item/Name
// AssignmentHistory/<WYYYYMMDD>/StudentItems/Item/Type
XmlNodeList listHistory = docAssignHistory.SelectNodes("AssignmentHistory/*/StudentItems/Item[Name='" + strStudent + "']");
foreach (XmlNode nodeHistoryItem in listHistory)
{
XmlNode weekNode = nodeHistoryItem.ParentNode.ParentNode;
String strWeekDate = weekNode.Name.Substring(1); // This skips the preceding "W"
DateTime dateHistoryItemWeekOfMeeting = new DateTime(Convert.ToInt32(strWeekDate.Substring(0, 4)),
Convert.ToInt32(strWeekDate.Substring(4, 2)),
Convert.ToInt32(strWeekDate.Substring(6, 2)));
if (dateHistoryItemWeekOfMeeting.Date > datWeekOfMeeting.Date)
{
StudentItem oItem = new StudentItem();
oItem.Week = dateHistoryItemWeekOfMeeting;
oItem.Type = nodeHistoryItem.SelectSingleNode("Type").InnerText;
oItem.Study = Convert.ToInt32(nodeHistoryItem.SelectSingleNode("Name").Attributes["Counsel"].Value);
listStudentItems.Add(oItem);
}
}
aryStudentItems = listStudentItems.ToArray();
}
catch (Exception ex)
{
SimpleLog.Log(ex);
}
}
第 4 步:
我编译 DLL。我遇到了一个问题:
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(4556,5): warning : 类型库导出器警告处理 'MSAToolsLibrary.StudentItem.k__BackingField,MSAToolsLibrary'。 警告:公共结构包含一个或多个非公共字段 将被导出。
【问题讨论】: