my other question出现新问题:尝试访问X12Segment的Fields属性时出现名义错误。
我遇到this question here并主动获取我的X12类型库的IDL。还附加了我的界面中的Fields属性的声明及其实现;是什么导致了这个错误?
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: <could not determine filename>
[
uuid(C0634D32-97A5-413A-8FC8-D6E0F4571F42),
version(1.0),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "X12, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
]
library X12
{
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface IX12Segment;
[
odl,
uuid(28A76274-05EE-45B2-A8EF-ADD5A5B351DE),
version(1.0),
dual,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "X12.IX12Segment")
]
interface IX12Segment : IDispatch {
[id(0x00000001), propget]
HRESULT SegmentType([out, retval] BSTR* pRetVal);
[id(0x00000001), propput]
HRESULT SegmentType([in] BSTR pRetVal);
[id(0x00000002), propget]
HRESULT Fields([out, retval] SAFEARRAY(BSTR)* pRetVal);
[id(0x00000002), propput]
HRESULT Fields([in] SAFEARRAY(BSTR) pRetVal);
[id(0x00000003), propget]
HRESULT FieldDelimiter([out, retval] BSTR* pRetVal);
[id(0x00000003), propput]
HRESULT FieldDelimiter([in] BSTR pRetVal);
[id(0x00000004), propget]
HRESULT SegmentDelimiter([out, retval] BSTR* pRetVal);
[id(0x00000004), propput]
HRESULT SegmentDelimiter([in] BSTR pRetVal);
[id(0x00000005), propget,
custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);
[id(0x00000006)]
HRESULT GetFieldEnum([out, retval] _Type** pRetVal);
};
[
uuid(B321599A-E5EC-4510-A021-E9A8B4D6293E),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "X12.X12Segment")
]
coclass X12Segment {
interface _Object;
[default] interface IX12Segment;
};
};
[Guid("28A76274-05EE-45B2-A8EF-ADD5A5B351DE"),
ComVisible(true)]
public interface IX12Segment
{
//More stuff goes here
[DispId(2)]
string[] Fields { get; set; }
//More stuff goes here
}
[Guid("B321599A-E5EC-4510-A021-E9A8B4D6293E"),
ClassInterface(ClassInterfaceType.None),
ComVisible(true)]
public class X12Segment : IX12Segment
{
protected ArrayList _fields;
protected short _minFields = -1;
protected short _maxFields = -1;
protected short[][] _fieldSizes = { new short[] { -1, -1 } };
//More stuff goes here
/// <summary>
/// Gets or sets all of the fields in the segment,
/// in the form of an array of strings.
/// </summary>
public string[] Fields
{
get
{
string[] o = new string[_fields.Count];
for (int i = 0; i < o.Length; i++)
{
o[i] = _fields[i].ToString();
}
return o;
}
set
{
ArrayList newFields = new ArrayList(value.Length);
for (int i = 0; i < value.Length; i++)
if (_fieldSizes[0][0] == -1 || value[i].Length <= _fieldSizes[i][1])
newFields.Add(value[i].ToCharArray());
else
throw new Exception("Attempt to store a value longer than the possible field size: \""
+ value[i] + "\" is larger than " + _fieldSizes[i] + " characters long.");
}
}
//More stuff goes here
}
答案 0 :(得分:1)
我在周末回来工作后做了一些关于此事的研究,显然VBA不与.NET相处就是问题。根据{{3}}并在this MSDN article中说明,似乎它不喜欢带有通过引用传递的数组的方法参数,并希望它们通过值传递。在MSDN文章中有一个解决VB.NET代码的方法,你只需告诉它按值传递设定值,但是在C#中定义访问器的参数似乎不可能。
我的解决方案是使Fields属性为只读,并且具有单独的方法来设置单个元素或整个shebang。
//Added these to the interface.
[DispId(aNumber)]
void SetField(int index, string value);
[DispId(aNumber)]
void SetFields(ref string[] fields);
//Added these two methods to the class,
//and removed the set accessor from the Fields property
/// <summary>
/// Set a field at the given index with a given value.
/// </summary>
/// <param name="index">Zero-based index of the field to set.</param>
/// <param name="value">The value to set the field with.</param>
public void SetField(int index, string value)
{
if (_fieldSizes[0][0] == -1 ||
(value.Length > _fieldSizes[index][0] && value.Length < _fieldSizes[index][1]))
_fields[index] = value.ToCharArray();
else
throw new ArgumentException("value", "Attempt to set a field with a value longer or shorter than the expected length.");
}
/// <summary>
/// Sets all the fields with the values in an array.
/// </summary>
/// <param name="fields">An array of strings containing the values.</param>
public void SetFields(ref string[] fields)
{
for (int i = 0; i < fields.Length; i++)
SetField(i, fields[i]);
}