Mik*_*nry 7 .net c# vbscript com-interop
我有一个.NET程序集,我通过COM互操作从VBScript(经典ASP)访问.一个类有一个索引器(也就是默认属性),我通过向索引器添加以下属性来从VBScript开始工作:[DispId(0)].它在大多数情况下都有效,但在作为另一个对象的成员访问类时却不行.
我怎样才能得到它的语法如下工作:Parent.Member("key")其中成员具有索引(类似访问的默认属性内置Request.QueryString:Request.QueryString("key"))?
在我的例子中,有一个父类TestRequest具有QueryString返回an 的属性,该属性IRequestDictionary具有默认的索引器.
VBScript示例:
Dim testRequest, testQueryString
Set testRequest = Server.CreateObject("AspObjects.TestRequest")
Set testQueryString = testRequest.QueryString
testQueryString("key") = "value"
Run Code Online (Sandbox Code Playgroud)
以下行导致错误而不是打印"值".这是我想要工作的语法:
Response.Write(testRequest.QueryString("key"))
Run Code Online (Sandbox Code Playgroud)
Microsoft VBScript运行时(0x800A01C2)
参数数量错误或属性赋值无效:'QueryString'
但是,下面的线做的工作没有错误和输出了预期的"值"(请注意,第一行访问的临时变量的默认索引):
Response.Write(testQueryString("key"))
Response.Write(testRequest.QueryString.Item("key"))
Run Code Online (Sandbox Code Playgroud)
下面是C#2.0中的简化接口和类.他们已通过RegAsm.exe /path/to/AspObjects.dll /codebase /tlb以下方式注册:
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequest {
IRequestDictionary QueryString { get; }
}
[ClassInterface(ClassInterfaceType.None)]
public class TestRequest : IRequest {
private IRequestDictionary _queryString = new RequestDictionary();
public IRequestDictionary QueryString {
get { return _queryString; }
}
}
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequestDictionary : IEnumerable {
[DispId(0)]
object this[object key] {
[DispId(0)] get;
[DispId(0)] set;
}
}
[ClassInterface(ClassInterfaceType.None)]
public class RequestDictionary : IRequestDictionary {
private Hashtable _dictionary = new Hashtable();
public object this[object key] {
get { return _dictionary[key]; }
set { _dictionary[key] = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试过研究和试验各种选项,但还没有找到解决方案.任何帮助将不胜感激,以弄清楚为什么testRequest.QueryString("key")语法不起作用以及如何使其工作.
注意:这是通过COM Interop公开索引器/默认属性的后续操作.
更新:以下是类型库中生成的IDL(使用oleview):
[
uuid(C6EDF8BC-6C8B-3AB2-92AA-BBF4D29C376E),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, AspObjects.IRequest)
]
dispinterface IRequest {
properties:
methods:
[id(0x60020000), propget]
IRequestDictionary* QueryString();
};
[
uuid(8A494CF3-1D9E-35AE-AFA7-E7B200465426),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, AspObjects.IRequestDictionary)
]
dispinterface IRequestDictionary {
properties:
methods:
[id(00000000), propget]
VARIANT Item([in] VARIANT key);
[id(00000000), propputref]
void Item(
[in] VARIANT key,
[in] VARIANT rhs);
};
Run Code Online (Sandbox Code Playgroud)
小智 7
我对这个问题的调查结果:
问题与公共语言运行时在向COM公开双接口和调度接口时使用的IDispatch实现有关.
像VBScript(ASP)这样的脚本语言在访问COM对象时使用OLE Automation IDispatch实现.
尽管它似乎有效,但我希望将该属性保留为属性,并且不希望具有某个功能(上面解释了解决方法).
您有两种可能的解决方案:
1 - 将弃用的IDispatchImplAttribute与IDispatchImplType.CompatibleImpl一起使用.
[ClassInterface(ClassInterfaceType.None)]
[IDispatchImpl(IDispatchImplType.CompatibleImpl)]
public class TestRequest : IRequest
{
private IRequestDictionary _queryString = new RequestDictionary();
public IRequestDictionary QueryString
{
get { return _queryString; }
}
}
Run Code Online (Sandbox Code Playgroud)
如MSDN中所述,此属性已弃用但仍可使用.Net 2.0,3.0,3.5,4.0.你必须决定它是否"弃用"这一事实对你来说可能是一个问题......
2 - 或者在类TesRequest中将IReflect实现为自定义IDispatch,或者创建一个实现IReflect的泛型类,并使您的类继承这个新创建的类.
通用类示例(interresting部分在InvokeMember方法中):
[ComVisible(false)]
public class CustomDispatch : IReflect
{
// Called by CLR to get DISPIDs and names for properties
PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr)
{
return this.GetType().GetProperties(bindingAttr);
}
// Called by CLR to get DISPIDs and names for fields
FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
{
return this.GetType().GetFields(bindingAttr);
}
// Called by CLR to get DISPIDs and names for methods
MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
{
return this.GetType().GetMethods(bindingAttr);
}
// Called by CLR to invoke a member
object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
{
try
{
// Test if it is an indexed Property
if (name != "Item" && (invokeAttr & BindingFlags.GetProperty) == BindingFlags.GetProperty && args.Length > 0 && this.GetType().GetProperty(name) != null)
{
object IndexedProperty = this.GetType().InvokeMember(name, invokeAttr, binder, target, null, modifiers, culture, namedParameters);
return IndexedProperty.GetType().InvokeMember("Item", invokeAttr, binder, IndexedProperty, args, modifiers, culture, namedParameters);
}
// default InvokeMember
return this.GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
}
catch (MissingMemberException ex)
{
// Well-known HRESULT returned by IDispatch.Invoke:
const int DISP_E_MEMBERNOTFOUND = unchecked((int)0x80020003);
throw new COMException(ex.Message, DISP_E_MEMBERNOTFOUND);
}
}
FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
{
return this.GetType().GetField(name, bindingAttr);
}
MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
{
return this.GetType().GetMember(name, bindingAttr);
}
MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
{
return this.GetType().GetMembers(bindingAttr);
}
MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr)
{
return this.GetType().GetMethod(name, bindingAttr);
}
MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr,
Binder binder, Type[] types, ParameterModifier[] modifiers)
{
return this.GetType().GetMethod(name, bindingAttr, binder, types, modifiers);
}
PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr,
Binder binder, Type returnType, Type[] types,
ParameterModifier[] modifiers)
{
return this.GetType().GetProperty(name, bindingAttr, binder,
returnType, types, modifiers);
}
PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr)
{
return this.GetType().GetProperty(name, bindingAttr);
}
Type IReflect.UnderlyingSystemType
{
get { return this.GetType().UnderlyingSystemType; }
}
}
Run Code Online (Sandbox Code Playgroud)
并为迈克的代码:
[ClassInterface(ClassInterfaceType.None)]
public class TestRequest : CustomDispatch, IRequest {
private IRequestDictionary _queryString = new RequestDictionary();
public IRequestDictionary QueryString {
get { return _queryString; }
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
几天前,我偶然发现了这个确切的问题。我找不到合理的解释,为什么它不起作用。
在花了很长时间尝试各种解决方法之后,我认为我终于找到了似乎可行的东西,而且还没有那么脏。我所做的是将容器对象中集合的访问器实现为方法而不是属性。此方法接收一个参数,即密钥。如果键为“ missing”或为null,则该方法返回该集合(它处理VbScript中的诸如“ testRequest.QueryString.Count”之类的表达式)。否则,该方法从集合中返回特定项。
这种方法的肮脏之处在于该方法返回一个对象(因为有时返回引用是集合,有时是集合的一项),因此从托管代码使用它需要在各处进行转换。为了避免这种情况,我在暴露集合的容器中创建了另一个属性(这次是一个适当的属性)。此属性不公开给COM。从C#/托管代码中,我使用此属性;从COM / VbScript /非托管代码中,我使用方法。
这是使用此线程的示例的上述解决方法的实现:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequest
{
IRequestDictionary ManagedQueryString { get; } // Property to use form managed code
object QueryString(object key); // Property to use from COM or unmanaged code
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class TestRequest : IRequest
{
private IRequestDictionary _queryString = new RequestDictionary();
public IRequestDictionary ManagedQueryString
{
get { return _queryString; }
}
public object QueryString(object key)
{
if (key is System.Reflection.Missing || key == null)
return _queryString;
else
return _queryString[key];
}
}
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequestDictionary : IEnumerable
{
[DispId(0)]
object this[object key]
{
[DispId(0)]
get;
[DispId(0)]
set;
}
int Count { get; }
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class RequestDictionary : IRequestDictionary
{
private Hashtable _dictionary = new Hashtable();
public object this[object key]
{
get { return _dictionary[key]; }
set { _dictionary[key] = value; }
}
public int Count { get { return _dictionary.Count; } }
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2637 次 |
| 最近记录: |