LogicalMethodInfo.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //
  2. // System.Web.Services.Protocols.LogicalMethodInfo.cs
  3. //
  4. // Authors:
  5. // Miguel de Icaza ([email protected])
  6. // Tim Coleman ([email protected])
  7. // Lluis Sanchez Gual ([email protected])
  8. //
  9. // Copyright (C) Tim Coleman, 2002
  10. // Copyright (C) Ximian, Inc, 2003
  11. //
  12. // TODO:
  13. // BeginInvoke, EndInvoke are missing.
  14. // AsyncResultParameter
  15. //
  16. // WILD GUESS:
  17. // The reason for this class is so that it can cluster method/begin/end methods
  18. // together, as the begin/end methods in generated files from WSDL does *NOT*
  19. // contain all the information required to make a request.
  20. //
  21. // Either that, or the Begin*/End* versions probe the attributes on the regular
  22. // method (which seems simpler).
  23. //
  24. using System.Reflection;
  25. using System.Collections;
  26. using System.Text;
  27. using System.Web.Services;
  28. namespace System.Web.Services.Protocols {
  29. public sealed class LogicalMethodInfo {
  30. #region Fields
  31. MethodInfo method_info, end_method_info;
  32. ParameterInfo [] parameters;
  33. ParameterInfo [] out_parameters;
  34. ParameterInfo [] in_parameters;
  35. #endregion // Fields.
  36. #region Constructors
  37. public LogicalMethodInfo (MethodInfo method_info)
  38. {
  39. if (method_info == null)
  40. throw new ArgumentNullException ("method_info should be non-null");
  41. if (method_info.IsStatic)
  42. throw new InvalidOperationException ("method is static");
  43. this.method_info = method_info;
  44. }
  45. //
  46. // Only an internal contructor, called from "Create"
  47. //
  48. LogicalMethodInfo (MethodInfo method_info, MethodInfo end_method_info)
  49. {
  50. if (method_info == null)
  51. throw new ArgumentNullException ("method_info should be non-null");
  52. if (method_info.IsStatic)
  53. throw new InvalidOperationException ("method is static");
  54. this.end_method_info = end_method_info;
  55. }
  56. #endregion // Constructors
  57. #region Properties
  58. //
  59. // Signatures for Begin/End methods:
  60. //
  61. // public System.IAsyncResult BeginHelloWorld(ARG1, ARG2, System.AsyncCallback callback, object asyncState) {
  62. // public string EndHelloWorld(System.IAsyncResult asyncResult) {
  63. public ParameterInfo AsyncCallbackParameter {
  64. get {
  65. ParameterInfo [] pi = method_info.GetParameters ();
  66. return pi [pi.Length-2];
  67. }
  68. }
  69. public ParameterInfo AsyncResultParameter {
  70. [MonoTODO]
  71. get { throw new NotImplementedException (); }
  72. }
  73. public ParameterInfo AsyncStateParameter {
  74. get {
  75. ParameterInfo [] pi = method_info.GetParameters ();
  76. return pi [pi.Length-1];
  77. }
  78. }
  79. public MethodInfo BeginMethodInfo {
  80. get {
  81. if (IsBeginMethod (method_info))
  82. return method_info;
  83. return null;
  84. }
  85. }
  86. public ICustomAttributeProvider CustomAttributeProvider {
  87. get {
  88. return method_info;
  89. }
  90. }
  91. public Type DeclaringType {
  92. get {
  93. return method_info.DeclaringType;
  94. }
  95. }
  96. public MethodInfo EndMethodInfo {
  97. get {
  98. return end_method_info;
  99. }
  100. }
  101. public ParameterInfo[] InParameters {
  102. get {
  103. if (parameters == null)
  104. ComputeParameters ();
  105. return in_parameters;
  106. }
  107. }
  108. public bool IsAsync {
  109. get {
  110. return IsBeginMethod (method_info) || IsEndMethod (method_info);
  111. }
  112. }
  113. public bool IsVoid {
  114. get {
  115. return method_info.ReturnType == typeof (void);
  116. }
  117. }
  118. public MethodInfo MethodInfo {
  119. get {
  120. return method_info;
  121. }
  122. }
  123. public string Name {
  124. get {
  125. return method_info.Name;
  126. }
  127. }
  128. void ComputeParameters ()
  129. {
  130. parameters = method_info.GetParameters ();
  131. int out_count = 0;
  132. int in_count = 0;
  133. foreach (ParameterInfo p in parameters){
  134. Type ptype = p.ParameterType;
  135. if (ptype.IsByRef){
  136. out_count++;
  137. if (!p.IsOut)
  138. in_count++;
  139. } else
  140. in_count++;
  141. }
  142. out_parameters = new ParameterInfo [out_count];
  143. int i = 0;
  144. for (int j = 0; j < parameters.Length; j++){
  145. if (parameters [j].ParameterType.IsByRef)
  146. out_parameters [i++] = parameters [j];
  147. }
  148. in_parameters = new ParameterInfo [in_count];
  149. i = 0;
  150. for (int j = 0; j < parameters.Length; j++){
  151. if (parameters [j].ParameterType.IsByRef){
  152. if (!parameters [j].IsOut)
  153. in_parameters [i++] = parameters [j];
  154. } else
  155. in_parameters [i++] = parameters [j];
  156. }
  157. }
  158. public ParameterInfo[] OutParameters {
  159. get {
  160. if (parameters == null)
  161. ComputeParameters ();
  162. return out_parameters;
  163. }
  164. }
  165. public ParameterInfo[] Parameters {
  166. get {
  167. if (parameters == null)
  168. ComputeParameters ();
  169. return parameters;
  170. }
  171. }
  172. public Type ReturnType {
  173. get {
  174. return method_info.ReturnType;
  175. }
  176. }
  177. public ICustomAttributeProvider ReturnTypeCustomAttributeProvider {
  178. get {
  179. return method_info.ReturnTypeCustomAttributes;
  180. }
  181. }
  182. #endregion // Properties
  183. #region Methods
  184. [MonoTODO]
  185. public IAsyncResult BeginInvoke (object target, object[] values, AsyncCallback callback, object asyncState)
  186. {
  187. throw new NotImplementedException ();
  188. }
  189. public static LogicalMethodInfo[] Create (MethodInfo[] method_infos)
  190. {
  191. return Create (method_infos, LogicalMethodTypes.Sync | LogicalMethodTypes.Async);
  192. }
  193. public static LogicalMethodInfo[] Create (MethodInfo[] method_infos, LogicalMethodTypes types)
  194. {
  195. ArrayList sync = ((types & LogicalMethodTypes.Sync) != 0) ? new ArrayList () : null;
  196. ArrayList begin, end;
  197. if ((types & LogicalMethodTypes.Async) != 0){
  198. begin = new ArrayList ();
  199. end = new ArrayList ();
  200. } else
  201. begin = end = null;
  202. foreach (MethodInfo mi in method_infos){
  203. if (IsBeginMethod (mi) && begin != null)
  204. begin.Add (mi);
  205. else if (IsEndMethod (mi) && end != null)
  206. end.Add (mi);
  207. else if (sync != null)
  208. sync.Add (mi);
  209. }
  210. int bcount = 0, count = 0;
  211. if (begin != null){
  212. bcount = count = begin.Count;
  213. if (count != end.Count)
  214. throw new InvalidOperationException ("Imbalance of begin/end methods");
  215. }
  216. if (sync != null)
  217. count += sync.Count;
  218. LogicalMethodInfo [] res = new LogicalMethodInfo [count];
  219. int dest = 0;
  220. if (begin != null){
  221. foreach (MethodInfo bm in begin){
  222. string end_name = "End" + bm.Name.Substring (5);
  223. for (int i = 0; i < bcount; i++){
  224. MethodInfo em = (MethodInfo) end [i];
  225. if (em.Name == end_name){
  226. res [dest++] = new LogicalMethodInfo (bm, em);
  227. break;
  228. }
  229. throw new InvalidOperationException ("Imbalance of begin/end methods");
  230. }
  231. }
  232. }
  233. if (sync != null)
  234. foreach (MethodInfo mi in sync){
  235. res [dest++] = new LogicalMethodInfo (mi);
  236. }
  237. return res;
  238. }
  239. [MonoTODO]
  240. public object[] EndInvoke (object target, IAsyncResult asyncResult)
  241. {
  242. throw new NotImplementedException ();
  243. }
  244. public object GetCustomAttribute (Type type)
  245. {
  246. return method_info.GetCustomAttributes (type, true) [0];
  247. }
  248. public object[] GetCustomAttributes (Type type)
  249. {
  250. return method_info.GetCustomAttributes (type, true);
  251. }
  252. public object[] Invoke (object target, object[] values)
  253. {
  254. if (parameters == null)
  255. ComputeParameters ();
  256. int retc = IsVoid ? 0 : 1;
  257. object [] ret = new object [retc + out_parameters.Length];
  258. object res = method_info.Invoke (target, values);
  259. if (retc == 1) ret [0] = res;
  260. int j = retc;
  261. for (int i = 0; i < parameters.Length; i++){
  262. if (parameters [i].ParameterType.IsByRef)
  263. ret [j++] = values [i];
  264. }
  265. return ret;
  266. }
  267. public static bool IsBeginMethod (MethodInfo method_info)
  268. {
  269. if (method_info == null)
  270. throw new ArgumentNullException ("method_info can not be null");
  271. if (method_info.ReturnType != typeof (IAsyncResult))
  272. return false;
  273. if (method_info.Name.StartsWith ("Begin"))
  274. return true;
  275. return false;
  276. }
  277. public static bool IsEndMethod (MethodInfo method_info)
  278. {
  279. if (method_info == null)
  280. throw new ArgumentNullException ("method_info can not be null");
  281. ParameterInfo [] parameter_info = method_info.GetParameters ();
  282. if (parameter_info.Length != 1)
  283. return false;
  284. if (parameter_info [0].ParameterType != typeof (IAsyncResult))
  285. return false;
  286. if (method_info.Name.StartsWith ("End"))
  287. return true;
  288. return false;
  289. }
  290. public override string ToString ()
  291. {
  292. StringBuilder sb = new StringBuilder ();
  293. if (parameters == null)
  294. ComputeParameters ();
  295. for (int i = 0; i < parameters.Length; i++){
  296. sb.Append (parameters [i].ParameterType);
  297. if (parameters [i].ParameterType.IsByRef)
  298. sb.Append (" ByRef");
  299. if (i+1 != parameters.Length)
  300. sb.Append (", ");
  301. }
  302. return String.Format (
  303. "{0} {1} ({2})",
  304. method_info.ReturnType, method_info.Name,
  305. sb.ToString ());
  306. }
  307. #endregion // Methods
  308. }
  309. }