2005-05-13 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic.CompilerServices / LateBinding.cs
1 //
2 // LateBinding.cs
3 //
4 // Author:
5 //   Chris J Breisch (cjbreisch@altavista.net) 
6 //   Marco Ridoni    (marco.ridoni@virgilio.it)
7 //   Dennis Hayes (dennish@raytek.com)
8 //   Satya Sudha K (ksathyasudha@novell.com)
9 //
10 // (C) 2002 Chris J Breisch
11 // (C) 2003 Marco Ridoni
12 //
13  /*
14   * Copyright (c) 2002-2003 Mainsoft Corporation.
15   * Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16   *
17   * Permission is hereby granted, free of charge, to any person obtaining a
18   * copy of this software and associated documentation files (the "Software"),
19   * to deal in the Software without restriction, including without limitation
20   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21   * and/or sell copies of the Software, and to permit persons to whom the
22   * Software is furnished to do so, subject to the following conditions:
23   * 
24   * The above copyright notice and this permission notice shall be included in
25   * all copies or substantial portions of the Software.
26   * 
27   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33   * DEALINGS IN THE SOFTWARE.
34   */
35 /**
36  *
37  */
38
39 using System;
40 using System.Reflection;
41 using Microsoft.VisualBasic;
42 using System.ComponentModel;
43
44
45 namespace Microsoft.VisualBasic.CompilerServices {
46         [StandardModule, EditorBrowsable(EditorBrowsableState.Never)]
47         sealed public class LateBinding {
48                 private LateBinding () {}
49
50                 [System.Diagnostics.DebuggerHiddenAttribute] 
51                 [System.Diagnostics.DebuggerStepThroughAttribute] 
52                 public static object LateGet(object o,
53                                              Type objType,
54                                              string name,
55                                              object[] args,
56                                              string[] paramnames,
57                                              bool[] CopyBack) {
58
59                         if (objType == null) {
60                                 if (o == null) {
61                                         throw new NullReferenceException();
62                                 }
63                                 objType = o.GetType();
64                         }
65
66                         IReflect objReflect = (IReflect) objType;
67
68                         BindingFlags flags = BindingFlags.FlattenHierarchy |
69                                              BindingFlags.IgnoreCase |
70                                              BindingFlags.Instance |
71                                              BindingFlags.Public |
72                                              BindingFlags.Static |
73                                              BindingFlags.GetProperty |
74                                              BindingFlags.InvokeMethod;
75
76                         if (name == null) {
77                                 name = "";
78                         }
79                         MemberInfo [] memberinfo = objReflect.GetMember (name, flags);
80
81                         if (memberinfo == null || memberinfo.Length == 0) {
82                                 throw new MissingMemberException ("Public Member '" + name + "' not found on type '" + objType + "'");
83                         }
84
85                         MemberInfo mi = GetMostDerivedMemberInfo (memberinfo);
86                         if (mi.MemberType == MemberTypes.Field) {
87                                 FieldInfo fi = (FieldInfo) mi;
88                                 object ret = fi.GetValue (o);
89                                 if (args != null && args.Length > 0) 
90                                         return LateIndexGet (ret, args, paramnames);
91                                 return ret;
92                         }
93
94                         VBBinder binder = new VBBinder (CopyBack);
95                         return binder.InvokeMember (name, flags, objType, objReflect, o, args, null, null, paramnames);
96                 }
97
98                 [System.Diagnostics.DebuggerStepThroughAttribute] 
99                 [System.Diagnostics.DebuggerHiddenAttribute] 
100                 public static void LateSetComplex(
101                         object o,
102                         Type objType,
103                         string name,
104                         object[] args,
105                         string[] paramnames,
106                         bool OptimisticSet,
107                         bool RValueBase) 
108                 {
109                         LateSet(o, objType, name, args, paramnames);
110                 }
111
112                 [System.Diagnostics.DebuggerStepThroughAttribute] 
113                 [System.Diagnostics.DebuggerHiddenAttribute] 
114                 public static void LateSet (object o,
115                                             Type objType,
116                                             string name,
117                                             object[] args,
118                                             string[] paramnames) {
119
120                         if (objType == null) {
121                                 if (o == null)
122                                         throw new NullReferenceException();
123                                 objType = o.GetType();
124                         }
125
126                         IReflect objReflect = (IReflect) objType;
127
128                         BindingFlags flags = BindingFlags.FlattenHierarchy |
129                                              BindingFlags.IgnoreCase |
130                                              BindingFlags.Instance |
131                                              BindingFlags.Public |
132                                              BindingFlags.Static |
133                                              BindingFlags.SetProperty |
134                                              BindingFlags.InvokeMethod;
135
136                         if (name == null) {
137                                 name = "";
138                         }
139
140                         MemberInfo [] memberinfo = objReflect.GetMember (name, flags);
141
142                         if (memberinfo == null || memberinfo.Length == 0) {
143                                 throw new MissingMemberException ("Public Member '" + name + "' not found on type '" + objType + "'");
144                         }
145
146                         MemberInfo mi = GetMostDerivedMemberInfo (memberinfo);
147                         if (mi.MemberType == MemberTypes.Field) {
148                                 FieldInfo fi = (FieldInfo) mi;
149                                 if (args == null || args.Length == 0) {
150                                         throw new MissingMemberException ("Public Member '" + name + "' not found on type '" + objType + "' that can be assigned the given set of arguments");
151                                 }
152
153                                 if (fi.IsInitOnly || fi.IsPrivate) {
154                                         throw new MissingMemberException ("Member '" + name + "' is a readonly field");
155                                 }
156
157                                 object value = null;
158                                 if (args.Length == 1)
159                                         value = args [0];
160
161                                 fi.SetValue (o, value);
162                                 return;
163                         }
164
165                         VBBinder binder = new VBBinder (null);
166                         binder.InvokeMember (name, flags, objType, objReflect, o, args, null, null, paramnames);
167                 }
168
169                 //mono implmentation
170                 //              [System.Diagnostics.DebuggerStepThroughAttribute] 
171                 //              [System.Diagnostics.DebuggerHiddenAttribute] 
172                 //              public static System.Object LateIndexGet (System.Object o, System.Object[] args, System.String[] paramnames)
173                 //              {
174                 //                      Type objType;
175                 //                      Object binderState = null;
176                 //      
177                 //                      if (o == null || args == null)
178                 //                              throw new ArgumentException();
179                 //      
180                 //                      objType = o.GetType();
181                 //                      if (objType.IsArray) {
182                 //                              Array a = (Array) o;
183                 //                              int[] idxs = new int[args.Length];
184                 //                              Array.Copy (args, idxs, args.Length);
185                 //      
186                 //                              return a.GetValue(idxs);
187                 //                      }
188                 //                      else
189                 //                      {
190                 //                              MemberInfo[] defaultMembers = objType.GetDefaultMembers();
191                 //                              if (defaultMembers == null)
192                 //                                      throw new Exception();  // FIXME: Which exception should we throw?
193                 //                                      
194                 //                              // We try to find a default method/property/field we can invoke/use
195                 //                              VBBinder MyBinder = new VBBinder();
196                 //                              BindingFlags bindingFlags = BindingFlags.IgnoreCase |
197                 //                                              BindingFlags.Instance |
198                 //                                              BindingFlags.Static |
199                 //                                              BindingFlags.Public |
200                 //                                              BindingFlags.GetProperty |
201                 //                                              BindingFlags.GetField |
202                 //                                              BindingFlags.InvokeMethod;
203                 //      
204                 //                              MethodBase[] mb = new MethodBase[defaultMembers.Length];
205                 //                              try {
206                 //                                      for (int x = 0; x < defaultMembers.Length; x++)
207                 //                                              if (defaultMembers[x].MemberType == MemberTypes.Property)
208                 //                                                      mb[x] = ((PropertyInfo) defaultMembers[x]).GetGetMethod();
209                 //                                              else
210                 //                                                      mb[x] = (MethodBase) defaultMembers[x];
211                 //                              } catch (Exception e) { }
212                 //      
213                 //                              MethodBase TheMethod = MyBinder.BindToMethod (bindingFlags,
214                 //                                                                              mb,
215                 //                                                                              ref args,
216                 //                                                                              null,
217                 //                                                                              null,
218                 //                                                                              paramnames,
219                 //                                                                              out binderState);
220                 //                              if (TheMethod == null)
221                 //                                      throw new TargetInvocationException(new ArgumentNullException());
222                 //                              
223                 //                              return TheMethod.Invoke (o, args);              
224                 //                      }
225                 //              }
226
227                 [System.Diagnostics.DebuggerStepThroughAttribute] 
228                 [System.Diagnostics.DebuggerHiddenAttribute] 
229                 public static object LateIndexGet(
230                         object o,
231                         object[] args,
232                         string[] paramnames) {
233                         if (o == null)
234                                 throw new NullReferenceException();
235                         if (args == null)
236                                 throw new NullReferenceException();
237                         Type type = o.GetType();
238                         //late binding for array
239
240                         if (type.IsArray) {
241                                 Array objAsArray = (Array) o;
242                                 if (objAsArray.Rank != args.Length)
243                                         throw new RankException ();
244
245                                 int numArgs = args.Length;
246                                 int [] indexArray = new int [numArgs];
247                                 for (int index = 0; index < numArgs; index ++) 
248                                         indexArray [index] = IntegerType.FromObject (args [index]);
249                                 return objAsArray.GetValue (indexArray);
250                         }
251
252                         //late binding for default property
253                         VBBinder binder = new VBBinder (null);
254                         BindingFlags flags = BindingFlags.FlattenHierarchy |
255                                              BindingFlags.IgnoreCase |
256                                              BindingFlags.Instance |
257                                              BindingFlags.Public |
258                                              BindingFlags.Static |
259                                              BindingFlags.GetProperty |
260                                              BindingFlags.InvokeMethod;
261                         IReflect objReflect = (IReflect) type;  
262                         return binder.InvokeMember ("", flags, type, objReflect, o, args, null, null, paramnames);
263                 }
264
265                 private static string getDefaultMemberName(Type type) {
266                         string defaultName = null;
267                         while (type != null) {
268                                 // TODO: 
269                                 throw new NotImplementedException("LateBinding not implmented");
270                                 //object[] locals =
271                                 //      type.GetCustomAttributes(
272                                 //      Type.GetType("System.Reflection.DefaultMemberAttribute"),
273                                 //      false);
274                                 //if (locals != null && locals.Length != 0) {
275                                 //      defaultName =
276                                 //              ((DefaultMemberAttribute) locals[0]).get_MemberName();
277                                 //      break;
278                                 //}
279                                 //type = type.get_BaseType();
280                         }
281                         return defaultName;
282                 }
283                 // mono implmentation
284                 //              [System.Diagnostics.DebuggerStepThroughAttribute]
285                 //              [System.Diagnostics.DebuggerHiddenAttribute]
286                 //              public static void LateIndexSet (System.Object o, System.Object[] args, System.String[] paramnames) 
287                 //              {
288                 //                      Type objType;
289                 //                      Object binderState = null;
290                 //                      Object myValue;
291                 //
292                 //                      if (o == null || args == null)
293                 //                              throw new ArgumentException();
294                 //      
295                 //                      myValue = args[args.Length - 1];
296                 //                      objType = o.GetType();
297                 //                      if (objType.IsArray) {
298                 //                              Array a = (Array) o;
299                 //                              int[] idxs = new int[args.Length - 1];
300                 //                              Array.Copy (args, idxs, args.Length -1);
301                 //                              a.SetValue(myValue, idxs);
302                 //                      }
303                 //                      else
304                 //                      {
305                 //                              MemberInfo[] defaultMembers = objType.GetDefaultMembers();
306                 //                              if (defaultMembers == null)
307                 //                                      throw new Exception();  // FIXME: Which exception should we throw?
308                 //                                                                      
309                 //                              // We try to find a default method/property/field we can invoke/use
310                 //                              VBBinder MyBinder = new VBBinder();
311                 //                              BindingFlags bindingFlags = BindingFlags.IgnoreCase |
312                 //                                              BindingFlags.Instance |
313                 //                                              BindingFlags.Static |
314                 //                                              BindingFlags.Public |
315                 //                                              BindingFlags.GetProperty |
316                 //                                              BindingFlags.GetField |
317                 //                                              BindingFlags.InvokeMethod;
318                 //
319                 //                              MethodBase[] mb = new MethodBase[defaultMembers.Length];
320                 //                              try {
321                 //                                      for (int x = 0; x < defaultMembers.Length; x++)
322                 //                                              if (defaultMembers[x].MemberType == MemberTypes.Property)
323                 //                                                      mb[x] = ((PropertyInfo) defaultMembers[x]).GetSetMethod();
324                 //                                              else
325                 //                                                      mb[x] = (MethodBase) defaultMembers[x];
326                 //                              } catch (Exception e) { }
327                 //      
328                 //                              MethodBase TheMethod = MyBinder.BindToMethod (bindingFlags,
329                 //                                                                              mb,
330                 //                                                                              ref args,
331                 //                                                                              null,
332                 //                                                                              null,
333                 //                                                                              paramnames,
334                 //                                                                              out binderState);
335                 //                              if (TheMethod == null)
336                 //                                      throw new TargetInvocationException(new ArgumentNullException());
337                 //                              
338                 //                              TheMethod.Invoke (o, args);     
339                 //                      }       
340                 //              }
341
342
343
344                 [System.Diagnostics.DebuggerHiddenAttribute]
345                 [System.Diagnostics.DebuggerStepThroughAttribute]
346                 public static void LateIndexSet(
347                         object o,
348                         object[] args,
349                         string[] paramnames) {
350                         if (o == null)
351                                 throw new NullReferenceException();
352                         if (args == null || args.Length == 0)
353                                 throw new NullReferenceException();
354                         Type type = o.GetType();
355                         //late binding for array
356                         if (type.IsArray) {
357                                 Array array = (Array) o;
358                                 if (array.Rank != args.Length - 1) 
359                                         throw new RankException ();
360                                 object setValue = args [args.GetUpperBound (0)];
361                                 int [] indexArray = new int [args.GetUpperBound (0)];
362                                 for (int index = 0; index < indexArray.Length; index ++) {
363                                         indexArray [index] = IntegerType.FromObject (args [index]);
364                                 }
365                                 array.SetValue (setValue, indexArray);
366                                 return;
367                         }
368                         //late binding for default property
369                         VBBinder binder = new VBBinder (null);
370                         BindingFlags flags = BindingFlags.FlattenHierarchy |
371                                              BindingFlags.IgnoreCase |
372                                              BindingFlags.Instance |
373                                              BindingFlags.Public |
374                                              BindingFlags.Static |
375                                              BindingFlags.SetProperty |
376                                              BindingFlags.InvokeMethod;
377                         IReflect objReflect = (IReflect) type;  
378                         binder.InvokeMember ("", flags, type, objReflect, o, args, null, null, paramnames);
379                 }
380
381                 [System.Diagnostics.DebuggerHiddenAttribute]
382                 [System.Diagnostics.DebuggerStepThroughAttribute]
383                 public static void LateIndexSetComplex(
384                         object o,
385                         object[] args,
386                         string[] paramnames,
387                         bool OptimisticSet,
388                         bool RValueBase) {
389                         LateIndexSet(o, args, paramnames);
390                 }
391
392                 [System.Diagnostics.DebuggerStepThroughAttribute]
393                 [System.Diagnostics.DebuggerHiddenAttribute]
394                 public static void LateCall(
395                         object o,
396                         Type objType,
397                         string name,
398                         object[] args,
399                         string[] paramnames,
400                         bool[] CopyBack) {
401
402                                 InternalLateCall (o, objType, name, args, paramnames, CopyBack, true);
403                 }
404
405                 [System.Diagnostics.DebuggerStepThroughAttribute]
406                 [System.Diagnostics.DebuggerHiddenAttribute]
407                 internal static object InternalLateCall( object o,
408                                                          Type objType,
409                                                          string name,
410                                                          object[] args,
411                                                          string[] paramnames,
412                                                          bool[] CopyBack, 
413                                                          bool IgnoreReturn) {
414                         if (objType == null) {
415                                 if (o == null) {
416                                         throw new NullReferenceException();
417                                 }
418                                 objType = o.GetType();
419                         }
420
421                         IReflect objReflect = (IReflect) objType;
422
423                         BindingFlags flags = BindingFlags.FlattenHierarchy |
424                                              BindingFlags.IgnoreCase |
425                                              BindingFlags.Instance |
426                                              BindingFlags.Public |
427                                              BindingFlags.Static |
428                                              BindingFlags.InvokeMethod;
429
430                         if (name == null) {
431                                 name = "";
432                         }
433                         MemberInfo [] memberinfo = objReflect.GetMember (name, flags);
434
435                         if (memberinfo == null || memberinfo.Length == 0) {
436                                 throw new MissingMemberException ("Public Member '" + name + "' not found on type '" + objType + "'");
437                         }
438
439                         if (args != null) {
440                                 foreach (MemberInfo mi in memberinfo) {
441                                         if (mi.MemberType == MemberTypes.Field) 
442                                                 throw new ArgumentException ("Expression '" + name + "' is not a procedure, but occurs as a target of a procedure call");
443                                 }
444                         }
445
446                         VBBinder binder = new VBBinder (CopyBack);
447                         return binder.InvokeMember (name, flags, objType, objReflect, o, args, null, null, paramnames);
448                 }
449
450                 private static MemberInfo GetMostDerivedMemberInfo (MemberInfo [] mi) 
451                 {
452                         if (mi == null || mi.Length == 0)
453                                 return null;
454                         MemberInfo m = mi [0];
455                         for (int index = 1; index < mi.Length; index ++) {
456                                 MemberInfo m1 = mi [index];
457                                 if (m1.DeclaringType.IsSubclassOf (m.DeclaringType))
458                                         m = m1;
459                         }
460                         return m;
461                 }               
462         }
463 }