/Microsoft.Scripting/Actions/MethodGroup.cs
C# | 192 lines | 131 code | 28 blank | 33 comment | 22 complexity | 7e2a29529400a61adbf954d719dc7cbb MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- using System.Diagnostics;
- #if CODEPLEX_40
- using System.Linq.Expressions;
- #else
- using Microsoft.Linq.Expressions;
- #endif
- using System.Reflection;
- using System.Threading;
- using Microsoft.Contracts;
-
- namespace Microsoft.Scripting.Actions {
- /// <summary>
- /// MethodGroup's represent a unique collection of method's. Typically this
- /// unique set is all the methods which are overloaded by the same name including
- /// methods with different arity. These methods represent a single logically
- /// overloaded element of a .NET type.
- ///
- /// The base DLR binders will produce MethodGroup's when provided with a MemberGroup
- /// which contains only methods. The MethodGroup's will be unique instances per
- /// each unique group of methods.
- /// </summary>
- public class MethodGroup : MemberTracker {
- private MethodTracker[] _methods;
- private Dictionary<TypeList, MethodGroup> _boundGenerics;
-
- internal MethodGroup(params MethodTracker[] methods) {
- _methods = methods;
- }
-
- public override TrackerTypes MemberType {
- get { return TrackerTypes.MethodGroup; }
- }
-
- public override Type DeclaringType {
- get { return _methods[0].DeclaringType; }
- }
-
- public override string Name {
- get { return _methods[0].Name; }
- }
-
- public bool ContainsInstance {
- get {
- foreach (MethodTracker mt in _methods) {
- if (!mt.IsStatic) return true;
- }
- return false;
- }
- }
-
- public bool ContainsStatic {
- get {
- foreach (MethodTracker mt in _methods) {
- if (mt.IsStatic) return true;
- }
- return false;
- }
- }
-
- public IList<MethodTracker> Methods {
- get {
- return _methods;
- }
- }
-
- public MethodBase[] GetMethodBases() {
- MethodBase[] methods = new MethodBase[Methods.Count];
- for (int i = 0; i < Methods.Count; i++) {
- methods[i] = Methods[i].Method;
- }
- return methods;
- }
-
- public override Expression GetValue(Expression context, ActionBinder binder, Type type) {
- return base.GetValue(context, binder, type);
- }
-
- public override MemberTracker BindToInstance(Expression instance) {
- if (ContainsInstance) {
- return new BoundMemberTracker(this, instance);
- }
-
- return this;
- }
-
- protected internal override Expression GetBoundValue(Expression context, ActionBinder binder, Type type, Expression instance) {
- return binder.ReturnMemberTracker(type, BindToInstance(instance));
- }
-
- /// <summary>
- /// Returns a BuiltinFunction bound to the provided type arguments. Returns null if the binding
- /// cannot be performed.
- /// </summary>
- public MethodGroup MakeGenericMethod(Type[] types) {
- TypeList tl = new TypeList(types);
-
- // check for cached method first...
- MethodGroup mg;
- if (_boundGenerics != null) {
- lock (_boundGenerics) {
- if (_boundGenerics.TryGetValue(tl, out mg)) {
- return mg;
- }
- }
- }
-
- // Search for generic targets with the correct arity (number of type parameters).
- // Compatible targets must be MethodInfos by definition (constructors never take
- // type arguments).
- List<MethodTracker> targets = new List<MethodTracker>(Methods.Count);
- foreach (MethodTracker mt in Methods) {
- MethodInfo mi = mt.Method;
- if (mi.ContainsGenericParameters && mi.GetGenericArguments().Length == types.Length)
- targets.Add((MethodTracker)MemberTracker.FromMemberInfo(mi.MakeGenericMethod(types)));
- }
-
- if (targets.Count == 0) {
- return null;
- }
-
- // Build a new MethodGroup that will contain targets with bound type arguments & cache it.
- mg = new MethodGroup(targets.ToArray());
-
- EnsureBoundGenericDict();
-
- lock (_boundGenerics) {
- _boundGenerics[tl] = mg;
- }
-
- return mg;
- }
-
- private void EnsureBoundGenericDict() {
- if (_boundGenerics == null) {
- Interlocked.CompareExchange<Dictionary<TypeList, MethodGroup>>(
- ref _boundGenerics,
- new Dictionary<TypeList, MethodGroup>(1),
- null);
- }
- }
-
- private class TypeList {
- private Type[] _types;
-
- public TypeList(Type[] types) {
- Debug.Assert(types != null);
- _types = types;
- }
-
- [Confined]
- public override bool Equals(object obj) {
- TypeList tl = obj as TypeList;
- if (tl == null || _types.Length != tl._types.Length) return false;
-
- for (int i = 0; i < _types.Length; i++) {
- if (_types[i] != tl._types[i]) return false;
- }
- return true;
- }
-
- [Confined]
- public override int GetHashCode() {
- int hc = 6551;
- foreach (Type t in _types) {
- hc = (hc << 5) ^ t.GetHashCode();
- }
- return hc;
- }
- }
- }
- }