Binding.cs
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license.
4 //
5 // Microsoft Bot Framework: http://botframework.com
6 //
7 // Bot Builder SDK GitHub:
8 // https://github.com/Microsoft/BotBuilder
9 //
10 // Copyright (c) Microsoft Corporation
11 // All rights reserved.
12 //
13 // MIT License:
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
35 using System;
36 using System.Collections.Generic;
37 using System.Linq;
38 using System.Reflection;
39 using System.Threading;
40 using System.Threading.Tasks;
41 
42 namespace Microsoft.Bot.Builder.Scorables.Internals
43 {
47  public interface IBinding
48  {
49  MethodBase Method { get; }
50  Task InvokeAsync(CancellationToken token);
51  }
52 
58  public interface IBinding<R> : IBinding
59  {
60  new Task<R> InvokeAsync(CancellationToken token);
61  }
62 
63  public class Binding : IBinding, IEquatable<Binding>
64  {
65  protected readonly MethodBase method;
66  protected readonly object instance;
67  protected readonly object[] arguments;
68 
69  public Binding(MethodBase method, object instance, object[] arguments)
70  {
71  SetField.NotNull(out this.method, nameof(method), method);
72  if (this.method.IsStatic)
73  {
74  this.instance = instance;
75  }
76  else
77  {
78  SetField.NotNull(out this.instance, nameof(instance), instance);
79  }
80 
81  SetField.NotNull(out this.arguments, nameof(arguments), arguments);
82  }
83 
84  MethodBase IBinding.Method => this.method;
85 
86  Task IBinding.InvokeAsync(CancellationToken token)
87  {
88  try
89  {
90  var arguments = MakeArguments(this.method, this.arguments, token);
91 
92  var result = this.method.Invoke(this.instance, arguments);
93  // if the result is a task, wait for its completion and propagate any exceptions
94  var task = result as Task;
95  if (task != null)
96  {
97  return task;
98  }
99 
100  return Task.CompletedTask;
101  }
102  catch (OperationCanceledException error)
103  {
104  return Task.FromCanceled(error.CancellationToken);
105  }
106  catch (Exception error)
107  {
108  return Task.FromException(error);
109  }
110  }
111 
112  public static object[] MakeArguments(MethodBase method, IReadOnlyList<object> source, CancellationToken token)
113  {
114  // late-bound provide the CancellationToken
115  var parameters = method.CachedParameters();
116  var target = new object[parameters.Count];
117  for (int index = 0; index < parameters.Count; ++index)
118  {
119  var type = parameters[index].ParameterType;
120  bool cancel = type.IsAssignableFrom(typeof(CancellationToken));
121  if (cancel)
122  {
123  var resolved = (CancellationToken)source[index];
124  if (resolved.CanBeCanceled)
125  {
126  // consider CancellationTokenSource.CreateLinkedTokenSource
127  // but remember to CancellationTokenSource.Dispose
128  throw new NotSupportedException();
129  }
130 
131  target[index] = token;
132  }
133  else
134  {
135  target[index] = source[index];
136  }
137  }
138 
139  return target;
140  }
141 
142  public override string ToString()
143  {
144  return this.method.ToString();
145  }
146 
147  public override int GetHashCode()
148  {
149  return this.method.GetHashCode();
150  }
151 
152  public override bool Equals(object other)
153  {
154  IEquatable<Binding> equatable = this;
155  return equatable.Equals(other as Binding);
156  }
157 
158  bool IEquatable<Binding>.Equals(Binding other)
159  {
160  return other != null
161  && object.Equals(this.method, other.method)
162  && object.Equals(this.instance, other.instance)
163  && Builder.Internals.Fibers.Extensions.Equals(this.arguments, other.arguments, EqualityComparer<object>.Default);
164  }
165  }
166 
167  public sealed class Binding<R> : Binding, IBinding<R>, IEquatable<Binding>
168  {
169  public Binding(MethodBase method, object instance, object[] arguments)
170  : base(method, instance, arguments)
171  {
172  }
173 
174  async Task<R> IBinding<R>.InvokeAsync(CancellationToken token)
175  {
176  var arguments = MakeArguments(this.method, this.arguments, token);
177 
178  var result = this.method.Invoke(this.instance, arguments);
179  // if the result is a task, wait for its completion and propagate any exceptions
180  var task = result as Task<R>;
181  if (task != null)
182  {
183  return await task;
184  }
185 
186  return (R) result;
187  }
188  }
189 }
Binding(MethodBase method, object instance, object[] arguments)
Definition: Binding.cs:69
Namespace for internal machinery that is not useful for most developers and may change in the future...
Represents a binding of arguments to a method&#39;s parameters.
Definition: Binding.cs:47
static object[] MakeArguments(MethodBase method, IReadOnlyList< object > source, CancellationToken token)
Definition: Binding.cs:112
Namespace for the internal fibers machinery that is not useful for most developers and may change in ...
Root namespace for the Microsoft Bot Builder SDK.