2009-07-01 1 views
2

Ich habe etwas Code, der die IReflect-Schnittstelle implementiert, um ein IDispatch-Gesicht auf einigen .NET-Objekten zu präsentieren, ohne alle COM-Interop-Go auf die Klassen selbst zu kleben.IReflect und DispId

Wir haben das verwendet, weil wir einen Scripting-Client hatten, der diese Klassen verwenden wollte, aber wir wollten nicht alle COM-Interop-Sachen auf die Klassen selbst legen.

Der Code ziemlich sieht wie folgt aus:

[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 
} 

Der Scripting-Client hat dann Code wie der folgende Anrufe in die Objekte (zB in VBScript) zu machen:

Set factory= CreateObject("My.Factory") 
set myObject = factory.CreateObject("MyDotNetType") 

myObject.DoSomething ' where DoSomething() is a method on MyDotNetType 

Mit dem Skript oben wird eine Instanz-AutoWrap, die eine Instanz von MyDotNetType umschließt, erstellt, und wenn der Client DoSomething aufruft, wird die InvokeMember-Methode auf AutoWrap aufgerufen, die sich dreht und DoSomething auf MyDotNetType aufruft.

Das alles funktioniert wunderbar in VBScript und Javascript.

Wenn Sie jedoch versuchen, dies aus Siebels eScript-Skriptsprache zu verwenden, schlagen die Dinge fehl, da eScript immer den Namen der Methode [DISPID = anyrandomnumber] in InvokeMember und nicht den Methodennamen wie VBScript eingibt.

Kennt jemand eine Möglichkeit, die Kontrolle über diese DispIDs aus dem .NET-Code zu bekommen? Ich habe ein paar verschiedenen Ansätze ausprobiert, von denen keines gearbeitet haben:

  • Rückkehr benutzerdefinierte Propertyinfo/Method Klassen von den anderen IReflect Mitgliedern, die eine DispIdAttribute von GetCustomAttributes
  • Reflection.Emiting eine Wrapper-Klasse zur Laufzeit zurück das hat die erforderlichen Attribute für COM verfügbar gemacht werden (nicht wirklich dies erwarten zu arbeiten, aber ich dachte, es würde versuchen)

TIA

Antwort

2

ich denke, Sie [DispID (1234) hinzufügen ] auf deinen Feldern zu kontrollieren w Hat die Dispid ist.

+0

Sie können auch obj.GetType(). IsValueType anstelle dieser switch-Anweisung verwenden. Marshal.IsComObject (Obj) ist auch sehr nützlich. –