LogicalMethodInfo.cs 8.8 KB

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