/* **************************************************************************** * * 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. * * * ***************************************************************************/ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq.Expressions; using System.Reflection; using System.Threading; using Microsoft.Contracts; namespace Microsoft.Scripting.Actions { /// /// 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. /// public class MethodGroup : MemberTracker { private MethodTracker[] _methods; private Dictionary _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 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)); } /// /// Returns a BuiltinFunction bound to the provided type arguments. Returns null if the binding /// cannot be performed. /// 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 targets = new List(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>( ref _boundGenerics, new Dictionary(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; } } } }