/// <summary> /// Provides a resolution for __new__. For standard .NET types __new__ resolves to their /// constructor. For Python types they inherit __new__ from their base class. /// /// TODO: Can we just always fallback to object.__new__? If not why not? /// </summary> private static MemberGroup/*!*/ NewResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { if (type.IsSealed && type.IsAbstract) { // static types don't have __new__ return MemberGroup.EmptyGroup; } bool isPythonType = typeof(IPythonObject).IsAssignableFrom(type); // check and see if __new__ has been overridden by the base type. foreach (Type t in binder.GetContributingTypes(type)) { if (!isPythonType && t == typeof(ObjectOps) && type != typeof(object)) { break; } MemberInfo[] news = t.GetMember("__new__"); if (news.Length > 0) { // type has a specific __new__ overload, return that for the constructor return GetExtensionMemberGroup(type, news); } } // type has no Python __new__, just return the .NET constructors if they have // a custom new ConstructorInfo[] ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);// CompilerHelpers.GetConstructors(type, binder.DomainManager.Configuration.PrivateBinding, true); ctors = CompilerHelpers.FilterConstructorsToPublicAndProtected(ctors); if (!PythonTypeOps.IsDefaultNew(ctors)) { return new MemberGroup(ctors); } // if no ctor w/ parameters are defined, fall back to object.__new__ which // will ignore all the extra arguments allowing the user to just override // __init__. return MemberGroup.EmptyGroup; }
/// <summary> /// Provides a resolution for __repr__ /// </summary> private static MemberGroup/*!*/ ReprResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { // __repr__ for normal .NET types is special, if we're a Python type then // we'll use one of the built-in reprs (from object or from the type) if (!PythonBinder.IsPythonType(type) && (!type.IsSealed || !type.IsAbstract)) { // static types don't get __repr__ // check and see if __repr__ has been overridden by the base type. foreach (Type t in binder.GetContributingTypes(type)) { if (t == typeof(ObjectOps) && type != typeof(object)) { break; } if (t.GetMember("__repr__").Length > 0) { // type has a specific __repr__ overload, pick it up normally later return MemberGroup.EmptyGroup; } } // no override, pick up the default fancy .NET __repr__ return binder.GetBaseInstanceMethod(type, "FancyRepr"); } return MemberGroup.EmptyGroup; }
/// <summary> /// Helper to see if the type explicitly overrides the method. This ignores members /// defined on object. /// </summary> private static bool TypeOverridesMethod(MemberBinder/*!*/ binder, Type/*!*/ type, string/*!*/ methodName) { // check and see if the method has been overridden by the base type. foreach (Type t in binder.GetContributingTypes(type)) { if (!PythonBinder.IsPythonType(type) && t == typeof(ObjectOps) && type != typeof(object)) { break; } MemberInfo[] reduce = t.GetMember(methodName); if (reduce.Length > 0) { // type has a specific overload return true; } } return false; }
public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, OldDynamicAction/*!*/ action, Type/*!*/ type, string/*!*/ name) { foreach (Type t in binder.GetContributingTypes(type)) { MemberGroup res = new MemberGroup(ArrayUtils.FindAll(t.GetMember(name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy), ProtectedOnly)); for (int i = 0; i < res.Count; i++) { MethodTracker meth = res[i] as MethodTracker; if (meth == null) { continue; } if (meth.Name == "Finalize" && meth.Method.GetBaseDefinition() == typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)) { MemberTracker[] retained = new MemberTracker[res.Count - 1]; if (res.Count == 1) { res = MemberGroup.EmptyGroup; } else { for (int j = 0; j < i; j++) { retained[j] = res[j]; } for (int j = i + 1; j < res.Count; j++) { retained[j - 1] = res[j]; } res = new MemberGroup(retained); } break; } } res = FilterSpecialNames(res, name, action); return GetBaseHelperOverloads(PythonTypeOps.GetFinalSystemType(type), name, res); } return MemberGroup.EmptyGroup; }
protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, OldDynamicAction/*!*/ action, Type/*!*/ type) { // these members are visible but only accept derived types. foreach (Type t in binder.GetContributingTypes(type)) { MemberInfo[] mems = ArrayUtils.FindAll(t.GetMembers(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic), ProtectedOnly); foreach (MemberInfo mi in mems) { yield return mi.Name; } } }
/// <summary> /// Provides a resolution for __iter__ /// </summary> private static MemberGroup/*!*/ IterResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { if (type == typeof(string)) { // __iter__ is only exposed in 3.0 if (binder.Binder.Context.PythonOptions.Python30) { return GetInstanceOpsMethod(type, "IterMethodForString"); } return MemberGroup.EmptyGroup; } if (typeof(Bytes).IsAssignableFrom(type)) { // __iter__ is only exposed in 3.0 if (binder.Binder.Context.PythonOptions.Python30) { return GetInstanceOpsMethod(type, "IterMethodForBytes"); } return MemberGroup.EmptyGroup; } foreach (Type t in binder.GetContributingTypes(type)) { MemberInfo[] news = t.GetMember("__iter__"); if (news.Length > 0) { // type has a specific __iter__ overload, we'll pick it up later return MemberGroup.EmptyGroup; } } if (!type.GetTypeInfo().IsDefined(typeof(DontMapIEnumerableToIterAttribute), true)) { // no special __iter__, use the default. if (typeof(IEnumerable<>).IsAssignableFrom(type)) { return GetInstanceOpsMethod(type, "IterMethodForGenericEnumerable"); } else if (typeof(IEnumerable).IsAssignableFrom(type)) { return GetInstanceOpsMethod(type, "IterMethodForEnumerable"); } else if (typeof(IEnumerator<>).IsAssignableFrom(type)) { return GetInstanceOpsMethod(type, "IterMethodForGenericEnumerator"); } else if (typeof(IEnumerator).IsAssignableFrom(type)) { return GetInstanceOpsMethod(type, "IterMethodForEnumerator"); } } return MemberGroup.EmptyGroup; }
public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, OldDynamicAction/*!*/ action, Type/*!*/ type, string/*!*/ name) { if (type.IsSealed && type.IsAbstract) { // static types don't have PythonOperationKind return MemberGroup.EmptyGroup; } // try mapping __*__ methods to .NET method names PythonOperationKind opMap; EnsureOperatorTable(); if (_pythonOperatorTable.TryGetValue(name, out opMap)) { if (IncludeOperatorMethod(type, opMap)) { OperatorMapping opInfo; if (IsReverseOperator(opMap)) { opInfo = OperatorMapping.GetOperatorMapping(opMap & ~PythonOperationKind.Reversed); } else { opInfo = OperatorMapping.GetOperatorMapping(opMap); } if (opInfo != null) { foreach (Type curType in binder.GetContributingTypes(type)) { if (curType == typeof(BigInteger) && (opInfo.Operator == PythonOperationKind.Mod || opInfo.Operator == PythonOperationKind.RightShift || opInfo.Operator == PythonOperationKind.LeftShift || opInfo.Operator == PythonOperationKind.Compare || opInfo.Operator == PythonOperationKind.Divide)) { // we override these with our own modulus/power PythonOperationKind which are different from BigInteger. continue; } Debug.Assert(opInfo.Name != "Equals"); MemberGroup res = GetBaseHelperOverloads(type, opInfo.Name, binder.GetMember(curType, opInfo.Name)); if (res.Count == 0 && opInfo.AlternateName != null) { res = binder.GetMember(curType, opInfo.AlternateName); if (opInfo.AlternateName == "Equals") { // "Equals" is available as an alternate method name. Because it's also on object and Python // doesn't define it on object we need to filter it out. res = FilterObjectEquality(res); } else { res = GetBaseHelperOverloads(type, opInfo.AlternateName, res); } } if (res.Count > 0) { return FilterForwardReverseMethods(name, res, type, opMap); } } } } } if (name == "__call__") { MemberGroup res = binder.GetMember(type, "Call"); if (res.Count > 0) { return res; } } return MemberGroup.EmptyGroup; }
public MemberGroup/*!*/ Resolver(MemberBinder/*!*/ binder, Type/*!*/ type) { if (type.IsSealed && type.IsAbstract) { // static types don't have PythonOperationKind return MemberGroup.EmptyGroup; } foreach (Type t in binder.GetContributingTypes(type)) { if (t == typeof(BigInteger)) continue; MemberGroup res = binder.GetMember(t, "op_Power"); if (res.Count > 0) { return FilterForwardReverseMethods(_pythonName, res, type, _op); } res = binder.GetMember(t, "Power"); if (res.Count > 0) { return FilterForwardReverseMethods(_pythonName, res, type, _op); } } return MemberGroup.EmptyGroup; }
public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, OldDynamicAction/*!*/ action, Type/*!*/ type, string/*!*/ name) { if (name == ".ctor" || name == ".cctor") return MemberGroup.EmptyGroup; // normal binding MemberGroup res; foreach (Type curType in binder.GetContributingTypes(type)) { res = GetBaseHelperOverloads(type, name, FilterSpecialNames(binder.GetMember(curType, name), name, action)); if (res.Count > 0) { return res; } } if (type.IsInterface) { foreach (Type t in type.GetInterfaces()) { res = FilterSpecialNames(binder.GetMember(t, name), name, action); if (res.Count > 0) { return res; } } } return MemberGroup.EmptyGroup; }
/// <summary> /// Provides a resolution for __hash__, first looking for IStructuralEquatable.GetHashCode, /// then IValueEquality.GetValueHashCode. /// </summary> private static MemberGroup/*!*/ HashResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { #if FEATURE_VALUE_EQUALITY if (typeof(IStructuralEquatable).IsAssignableFrom(type) && !type.IsInterface()) { #else if ((typeof(IStructuralEquatable).IsAssignableFrom(type) || typeof(IValueEquality).IsAssignableFrom(type)) && !type.IsInterface) { #endif // check and see if __hash__ has been overridden by the base type. foreach (Type t in binder.GetContributingTypes(type)) { // if it's defined on object, it's not overridden if (t == typeof(ObjectOps) || t == typeof(object)) { break; } MemberInfo[] hash = t.GetMember("__hash__"); if (hash.Length > 0) { return MemberGroup.EmptyGroup; } } #if FEATURE_VALUE_EQUALITY return GetInstanceOpsMethod(type, "StructuralHashMethod"); #else if (typeof(IStructuralEquatable).IsAssignableFrom(type)) { return GetInstanceOpsMethod(type, "StructuralHashMethod"); } if (typeof(IValueEquality).IsAssignableFrom(type)) { return new MemberGroup(typeof(IValueEquality).GetMethod("GetValueHashCode")); } #endif } // otherwise we'll pick up __hash__ from ObjectOps which will call .NET's .GetHashCode therefore // we don't explicitly search to see if the object overrides GetHashCode here. return MemberGroup.EmptyGroup; }
/// <summary> /// Helper to get the proper typecasting method, according to the following precedence rules: /// /// 1. Strongest (most specific) declaring type /// 2. Strongest (most specific) parameter type /// 3. Type of conversion /// i. Implicit /// ii. Explicit /// 4. Return type (order specified in toTypes) /// </summary> private static MethodInfo FindCastMethod(MemberBinder/*!*/ binder, Type/*!*/ fromType, List<Type>/*!*/ toTypes) { MethodInfo cast = null; ParameterInfo[] castParams = null; foreach (Type t in binder.GetContributingTypes(fromType)) { foreach (string castName in CastNames) { foreach (MemberInfo member in t.GetMember(castName)) { MethodInfo method; ParameterInfo[] methodParams; // Necessary conditions if (member.MemberType != MemberTypes.Method) { continue; } method = (MethodInfo)member; if (!toTypes.Contains(method.ReturnType) || (methodParams = method.GetParameters()).Length != 1) { continue; } // Precedence rule 1 if (cast == null || method.DeclaringType.IsSubclassOf(cast.DeclaringType)) { cast = method; castParams = methodParams; continue; } else if (method.DeclaringType != cast.DeclaringType) { continue; } // Precedence rule 2 if (methodParams[0].ParameterType.IsSubclassOf(castParams[0].ParameterType)) { cast = method; castParams = methodParams; continue; } else if (castParams[0].ParameterType != methodParams[0].ParameterType) { continue; } // Precedence rule 3 if (method.Name != cast.Name) { if (method.Name == "op_Implicit") { cast = method; castParams = methodParams; } continue; } // Precedence rule 4: foreach (Type toType in toTypes) { if (method.ReturnType == toType) { cast = method; castParams = methodParams; } else if (cast.ReturnType == toType) { break; } } } } } return cast; }
protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) { // these members are visible but only accept derived types. foreach (Type t in binder.GetContributingTypes(type)) { foreach (MemberInfo mi in t.GetMembers(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) { if (ProtectedOnly(mi)) { yield return mi.Name; } } } }
public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) { foreach (Type t in binder.GetContributingTypes(type)) { MemberGroup res = new MemberGroup( t.GetMember(name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) .Where(ProtectedOnly) .ToArray()); for (int i = 0; i < res.Count; i++) { MethodTracker meth = res[i] as MethodTracker; if (meth == null) { continue; } if (meth.Name == "Finalize" && meth.Method.GetBaseDefinition() == typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)) { MemberTracker[] retained = new MemberTracker[res.Count - 1]; if (res.Count == 1) { res = MemberGroup.EmptyGroup; } else { for (int j = 0; j < i; j++) { retained[j] = res[j]; } for (int j = i + 1; j < res.Count; j++) { retained[j - 1] = res[j]; } res = new MemberGroup(retained); } break; } } return FilterSpecialNames(res, name, action); } return MemberGroup.EmptyGroup; }
public MemberGroup/*!*/ Resolver(MemberBinder/*!*/ binder, Type/*!*/ type) { if (type.IsSealed() && type.IsAbstract()) { // static types don't have PythonOperationKind return MemberGroup.EmptyGroup; } foreach (Type t in binder.GetContributingTypes(type)) { MemberGroup res = binder.GetMember(t, _methodName); if (res.Count > 0) { return FilterForwardReverseMethods(_pythonName, res, type, _op); } } return MemberGroup.EmptyGroup; }
/// <summary> /// Provides a resolution for __iter__ /// </summary> private static MemberGroup/*!*/ IterResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { // no __iter__ on string, just __getitem__ if (type != typeof(string)) { if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type)) { foreach (Type t in binder.GetContributingTypes(type)) { MemberInfo[] news = t.GetMember("__iter__"); if (news.Length > 0) { // type has a specific __i__ overload, we'll pick it up later return MemberGroup.EmptyGroup; } } // no special __iter__, use the default. return GetInstanceOpsMethod(type, "IterMethod"); } } return MemberGroup.EmptyGroup; }
protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, OldDynamicAction/*!*/ action, Type/*!*/ type) { foreach (Type curType in binder.GetContributingTypes(type)) { foreach (MemberInfo mi in curType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (mi.MemberType == MemberTypes.Method) { MethodInfo meth = (MethodInfo)mi; if (meth.IsSpecialName) { if (meth.IsDefined(typeof(PropertyMethodAttribute), true)) { if (meth.Name.StartsWith("Get") || meth.Name.StartsWith("Set")) { yield return meth.Name.Substring(3); } else { Debug.Assert(meth.Name.StartsWith("Delete")); yield return meth.Name.Substring(6); } } continue; } } yield return mi.Name; } } }
/// <summary> /// Looks for an Equals overload defined on the type and if one is present binds __ne__ to an /// InstanceOps helper. /// </summary> private static MemberGroup/*!*/ FallbackInequalityResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { // if object defines __eq__ then we can call the reverse version if (IncludeOperatorMethod(type, PythonOperationKind.NotEqual)) { foreach (Type curType in binder.GetContributingTypes(type)) { MemberGroup mg = binder.GetMember(curType, "Equals"); foreach (MemberTracker mt in mg) { if (mt.MemberType != TrackerTypes.Method || mt.DeclaringType == typeof(object)) { continue; } MethodTracker method = (MethodTracker)mt; if ((method.Method.Attributes & MethodAttributes.NewSlot) != 0) { continue; } ParameterInfo[] pis = method.Method.GetParameters(); if (pis.Length == 1) { if (pis[0].ParameterType == typeof(object)) { return new MemberGroup(MethodTracker.FromMemberInfo(typeof(InstanceOps).GetMethod("NotEqualsMethod"), curType)); } } } } } return MemberGroup.EmptyGroup; }
/// <summary> /// Provides a resolution for IValueEquality.GetValueHashCode to __hash__. /// </summary> private static MemberGroup/*!*/ HashResolver(MemberBinder/*!*/ binder, Type/*!*/ type) { if (typeof(IValueEquality).IsAssignableFrom(type) && !type.IsInterface) { // check and see if __new__ has been overridden by the base type. foreach (Type t in binder.GetContributingTypes(type)) { if (t == typeof(ObjectOps) || t == typeof(object)) { break; } MemberInfo[] hash = t.GetMember("__hash__"); if (hash.Length > 0) { return MemberGroup.EmptyGroup; } } return new MemberGroup(typeof(IValueEquality).GetMethod("GetValueHashCode")); } // otherwise we'll pick up __hash__ from ObjectOps which will call .NET's .GetHashCode therefore // we don't explicitly search to see if the object overrides GetHashCode here. return MemberGroup.EmptyGroup; }