У меня есть код, который реализует интерфейс IReflect для представления лица IDispatch на некоторые объекты .NET, не приклеивая все COM-взаимодействия к самим классам.
Мы использовали это, потому что у нас был клиент сценариев, который хотел использовать эти классы, но мы не хотели помещать все материалы взаимодействия COM в сами классы.
Код выглядит примерно так:
[ComVisible(true)]
[ProgId("My.Factory")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MyFactory
{
public object CreateObject(string type)
{
return new AutoWrap(Activator.CreateInstance(Type.GetType(type)));
}
}
[ProgId("My.AutoWrap")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComVisible(true)]
[Guid("72EAFB10-099F-4e96-A17E-B67E34DACA53")]
public class AutoWrap : IReflect
{
protected object O = null;
protected Type T = null;
public AutoWrap()
{
}
public AutoWrap(object obj)
{
O = obj;
T = O.GetType();
}
#region IReflect Members
public System.Reflection.FieldInfo GetField(string name, System.Reflection.BindingFlags bindingAttr)
{
return T.GetField(name, bindingAttr);
}
/* SNIP other IReflect methods */
public object InvokeMember(string name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object target, object[] args, System.Reflection.ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
{
// Unwrap any AutoWrap'd objects (they need to be raw if a paramater)
if (args != null && args.Length > 0)
{
for (int x = 0; x < args.Length; x++)
{
if (args[x] is AutoWrap)
{
args[x] = ((AutoWrap)args[x]).O;
}
}
}
// Invoke whatever needs be invoked!
object obj = T.InvokeMember(name, invokeAttr, binder, O, args, modifiers, culture, namedParameters);
// Wrap any return objects (that are not primative types)
if (obj != null)
{
switch (obj.GetType().ToString())
{
case "System.String":
case "System.DateTime":
case "System.Boolean":
case "System.Byte":
case "System.Char":
case "System.Decimal":
case "System.Double":
case "System.Single": // Float
case "System.Int32":
case "System.Int64": // Long
case "System.SByte":
case "System.Int16": // Short
case "System.UInt32":
case "System.UInt64":
case "System.UInt16":
break; // These Types do not get wrapped
default:
obj = new AutoWrap(obj); // Wrap Type
break;
}
}
return obj;
}
public object UnderlyingObject
{
get
{
return O;
}
}
public Type UnderlyingSystemType
{
get { return T.UnderlyingSystemType; }
}
#endregion
}
Затем клиент сценариев имеет код, подобный следующему, для совершения вызовов в объектах (пример в VBScript):
Set factory= CreateObject("My.Factory")
set myObject = factory.CreateObject("MyDotNetType")
myObject.DoSomething ' where DoSomething() is a method on MyDotNetType
С помощью script выше будет создан экземпляр AutoWrap, который обертывает экземпляр MyDotNetType, и когда клиент вызывает DoSomething, метод InvokeMember будет вызван в AutoWrap, который оборачивается и вызывает DoSomething в MyDotNetType.
Все это прекрасно работает в VBScript и в Javascript.
Однако, пытаясь использовать это на языке скриптов Siebel eScript, все выходит из строя, потому что eScript всегда проходит в [DISPID = somerandomnumber] как имя в InvokeMember, а не в имени метода, как это делает VBScript.
Кто-нибудь знает, как получить контроль над этими DispID из кода .NET? Я пробовал несколько разных подходов, ни один из которых не работал:
ТИА
Я думаю, что вы можете добавить [DispId (1234)] в свои поля, чтобы контролировать, что такое отчаяние.