⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memberlookuphelper.cs

📁 SharpDevelop2.0.0 c#开发免费工具
💻 CS
📖 第 1 页 / 共 2 页
字号:
					break;
				if (!InferTypeArgument(parameters[i].ReturnType, arguments[i], result)) {
					// inferring failed: maybe this is a params parameter that must be expanded?
					if (parameters[i].IsParams && parameters[i].ReturnType.ArrayDimensions == 1) {
						InferTypeArgument(parameters[i].ReturnType.ArrayElementType, arguments[i], result);
					}
				}
			}
			// only return the result array when there something was inferred
			for (int i = 0; i < result.Length; i++) {
				if (result[i] != null) {
					return result;
				}
			}
			return null;
		}
		
		public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray)
		{
			if (passedArgument == null) return true; // TODO: NullTypeReference
			if (expectedArgument != null && expectedArgument.ArrayDimensions > 0) {
				if (expectedArgument.ArrayDimensions == passedArgument.ArrayDimensions) {
					return InferTypeArgument(expectedArgument.ArrayElementType, passedArgument.ArrayElementType, outputArray);
				} else if (passedArgument.TypeArguments != null) {
					switch (passedArgument.FullyQualifiedName) {
						case "System.Collections.Generic.IList":
						case "System.Collections.Generic.ICollection":
						case "System.Collections.Generic.IEnumerable":
							return InferTypeArgument(expectedArgument.ArrayElementType, passedArgument.TypeArguments[0], outputArray);
					}
				}
				// If P is an array type, and A is not an array type of the same rank,
				// or an instantiation of IList<>, ICollection<>, or IEnumerable<>, then
				// type inference fails for the generic method.
				return false;
			}
			GenericReturnType methodTP = expectedArgument as GenericReturnType;
			if (methodTP != null && methodTP.TypeParameter.Method != null) {
				if (methodTP.TypeParameter.Index < outputArray.Length) {
					outputArray[methodTP.TypeParameter.Index] = passedArgument;
				}
				return true;
			}
			if (expectedArgument.TypeArguments != null) {
				// The spec for this case is quite complex.
				// For our purposes, we can simplify enourmously:
				if (passedArgument.TypeArguments == null) return false;
				int count = Math.Min(expectedArgument.TypeArguments.Count, passedArgument.TypeArguments.Count);
				for (int i = 0; i < count; i++) {
					InferTypeArgument(expectedArgument.TypeArguments[i], passedArgument.TypeArguments[i], outputArray);
				}
			}
			return true;
		}
		#endregion
		
		#region IsApplicable
		static bool IsApplicable(IList<IParameter> parameters,
		                         IReturnType[] arguments,
		                         bool allowAdditionalArguments,
		                         out int score,
		                         out bool expanded)
		{
			// see ECMA-334, § 14.4.2.1
			// TODO: recognize ref/out (needs info about passing mode for arguments, you have to introduce RefReturnType)
			
			expanded = false;
			score = 0;
			if (parameters.Count == 0)
				return arguments.Length == 0;
			if (!allowAdditionalArguments && parameters.Count > arguments.Length + 1)
				return false;
			int lastParameter = parameters.Count - 1;
			
			// check all arguments except the last
			bool ok = true;
			for (int i = 0; i < Math.Min(lastParameter, arguments.Length); i++) {
				if (IsApplicable(arguments[i], parameters[i].ReturnType)) {
					score++;
				} else {
					ok = false;
				}
			}
			if (!ok) {
				return false;
			}
			if (parameters.Count == arguments.Length) {
				// try if method is applicable in normal form by checking last argument
				if (IsApplicable(arguments[lastParameter], parameters[lastParameter].ReturnType)) {
					return true;
				}
			}
			// method is not applicable in normal form, try expanded form:
			// - last parameter must be params array
			if (!parameters[lastParameter].IsParams) {
				return false;
			}
			expanded = true;
			score++;
			
			// - all additional parameters must be applicable to the unpacked array
			IReturnType rt = parameters[lastParameter].ReturnType;
			if (rt == null || rt.ArrayDimensions == 0) {
				return false;
			}
			for (int i = lastParameter; i < arguments.Length; i++) {
				if (IsApplicable(arguments[i], rt.ArrayElementType)) {
					score++;
				} else {
					ok = false;
				}
			}
			return ok;
		}
		
		static bool IsApplicable(IReturnType argument, IReturnType expected)
		{
			if (argument == null) // TODO: Use NullReturnType instead of no return type
				return true; // "null" can be passed for any argument
			if (expected is GenericReturnType) {
				foreach (IReturnType constraint in ((GenericReturnType)expected).TypeParameter.Constraints) {
					if (!ConversionExists(argument, constraint)) {
						return false;
					}
				}
			}
			return ConversionExists(argument, expected);
		}
		#endregion
		
		#region Conversion exists
		/// <summary>
		/// Checks if an implicit conversion exists from <paramref name="from"/> to <paramref name="to"/>.
		/// </summary>
		public static bool ConversionExists(IReturnType from, IReturnType to)
		{
			// ECMA-334, § 13.1 Implicit conversions
			
			// Identity conversion:
			if (from == to) return true;
			if (from == null || to == null) return false;
			if (from.Equals(to)) {
				return true;
			}
			
			bool fromIsDefault = from.IsDefaultReturnType;
			bool toIsDefault = to.IsDefaultReturnType;
			
			if (fromIsDefault && toIsDefault) {
				// Implicit numeric conversions:
				int f = GetPrimitiveType(from);
				int t = GetPrimitiveType(to);
				if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal))
					return true;
				if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal))
					return true;
				if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal))
					return true;
				if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal))
					return true;
				if (f == Int && (t == Long || t == Float || t == Double || t == Decimal))
					return true;
				if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal))
					return true;
				if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal))
					return true;
				if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal))
					return true;
				if (f == Float && t == Double)
					return true;
			}
			// Implicit reference conversions:
			
			if (toIsDefault && to.FullyQualifiedName == "System.Object") {
				return true; // from any type to object
			}
			if (toIsDefault && (fromIsDefault || from.ArrayDimensions > 0)) {
				IClass c1 = from.GetUnderlyingClass();
				IClass c2 = to.GetUnderlyingClass();
				if (c1 != null && c1.IsTypeInInheritanceTree(c2)) {
					return true;
				}
			}
			if (from.ArrayDimensions > 0 && from.ArrayDimensions == to.ArrayDimensions) {
				// from array to other array type
				return ConversionExists(from.ArrayElementType, to.ArrayElementType);
			}
			IList<IReturnType> fromTypeArguments = from.TypeArguments;
			IList<IReturnType> toTypeArguments = to.TypeArguments;
			if (fromTypeArguments != null && toTypeArguments != null) {
				if (from.FullyQualifiedName == to.FullyQualifiedName) {
					if (fromTypeArguments.Count == toTypeArguments.Count) {
						for (int i = 0; i < fromTypeArguments.Count; i++) {
							if (fromTypeArguments[i] == toTypeArguments[i])
								continue;
							if (object.Equals(fromTypeArguments[i], toTypeArguments[i]))
								continue;
							if (!(toTypeArguments[i] is GenericReturnType))
								return false;
						}
						return true;
					}
				}
			}
			
			return false;
		}
		#endregion
		
		#region Better conversion
		/// <summary>
		/// Gets if the conversion from <paramref name="from"/> to <paramref name="to1"/> is better than
		/// the conversion from <paramref name="from"/> to <paramref name="to2"/>.
		/// </summary>
		/// <returns>
		/// 0 = neither conversion is better<br/>
		/// 1 = from -> to1 is the better conversion<br/>
		/// 2 = from -> to2 is the better conversion.
		/// </returns>
		public static int GetBetterConversion(IReturnType from, IReturnType to1, IReturnType to2)
		{
			if (from == null) return 0;
			if (to1 == null) return 2;
			if (to2 == null) return 1;
			
			// See ECMA-334, § 14.4.2.3
			
			// If T1 and T2 are the same type, neither conversion is better.
			if (to1.Equals(to2)) {
				return 0;
			}
			// If S is T1, C1 is the better conversion.
			if (from.Equals(to1)) {
				return 1;
			}
			// If S is T2, C2 is the better conversion.
			if (from.Equals(to2)) {
				return 2;
			}
			bool canConvertFrom1To2 = ConversionExists(to1, to2);
			bool canConvertFrom2To1 = ConversionExists(to2, to1);
			// If an implicit conversion from T1 to T2 exists, and no implicit conversion
			// from T2 to T1 exists, C1 is the better conversion.
			if (canConvertFrom1To2 && !canConvertFrom2To1) {
				return 1;
			}
			// If an implicit conversion from T2 to T1 exists, and no implicit conversion
			// from T1 to T2 exists, C2 is the better conversion.
			if (canConvertFrom2To1 && !canConvertFrom1To2) {
				return 2;
			}
			if (to1.IsDefaultReturnType && to2.IsDefaultReturnType) {
				return GetBetterPrimitiveConversion(to1, to2);
			}
			// Otherwise, neither conversion is better.
			return 0;
		}
		
		const int Byte   = 1;
		const int Short  = 2;
		const int Int    = 3;
		const int Long   = 4;
		const int SByte  = 5;
		const int UShort = 6;
		const int UInt   = 7;
		const int ULong  = 8;
		const int Float  = 9;
		const int Double = 10;
		const int Char   = 11;
		const int Decimal= 12;
		
		static int GetBetterPrimitiveConversion(IReturnType to1, IReturnType to2)
		{
			int t1 = GetPrimitiveType(to1);
			int t2 = GetPrimitiveType(to2);
			if (t1 == 0 || t2 == 0) return 0; // not primitive
			if (t1 == SByte && (t2 == Byte || t2 == UShort || t2 == UInt || t2 == ULong))
				return 1;
			if (t2 == SByte && (t1 == Byte || t1 == UShort || t1 == UInt || t1 == ULong))
				return 2;
			if (t1 == Short && (t2 == UShort || t2 == UInt || t2 == ULong))
				return 1;
			if (t2 == Short && (t1 == UShort || t1 == UInt || t1 == ULong))
				return 2;
			if (t1 == Int && (t2 == UInt || t2 == ULong))
				return 1;
			if (t2 == Int && (t1 == UInt || t1 == ULong))
				return 2;
			if (t1 == Long && t2 == ULong)
				return 1;
			if (t2 == Long && t1 == ULong)
				return 2;
			return 0;
		}
		
		static int GetPrimitiveType(IReturnType t)
		{
			switch (t.FullyQualifiedName) {
					case "System.SByte": return SByte;
					case "System.Byte": return Byte;
					case "System.Int16": return Short;
					case "System.UInt16": return UShort;
					case "System.Int32": return Int;
					case "System.UInt32": return UInt;
					case "System.Int64": return Long;
					case "System.UInt64": return ULong;
					case "System.Single": return Float;
					case "System.Double": return Double;
					case "System.Char": return Char;
					case "System.Decimal": return Decimal;
					default: return 0;
			}
		}
		#endregion
		
		/// <summary>
		/// Gets the common base type of a and b.
		/// </summary>
		public static IReturnType GetCommonType(IReturnType a, IReturnType b)
		{
			if (a == null) return b;
			if (b == null) return a;
			if (ConversionExists(a, b))
				return b;
			if (ConversionExists(b, a))
				return a;
			IClass c = a.GetUnderlyingClass();
			if (c != null) {
				foreach (IClass baseClass in c.ClassInheritanceTree) {
					IReturnType baseType = baseClass.DefaultReturnType;
					if (baseClass.TypeParameters.Count > 0) {
						IReturnType[] typeArguments = new IReturnType[baseClass.TypeParameters.Count];
						for (int i = 0; i < typeArguments.Length; i++) {
							typeArguments[i] = GetTypeParameterPassedToBaseClass(a, baseClass, i);
						}
						baseType = new ConstructedReturnType(baseType, typeArguments);
					}
					if (ConversionExists(b, baseType))
						return baseType;
				}
			}
			return ReflectionReturnType.Object;
		}
		
		/// <summary>
		/// Gets the type parameter that was passed to a certain base class.
		/// For example, when <paramref name="returnType"/> is Dictionary(of string, int)
		/// this method will return KeyValuePair(of string, int)
		/// </summary>
		public static IReturnType GetTypeParameterPassedToBaseClass(IReturnType returnType, IClass baseClass, int baseClassTypeParameterIndex)
		{
			IClass c = returnType.GetUnderlyingClass();
			if (c == null) return null;
			if (baseClass.CompareTo(c) == 0) {
				if (returnType.TypeArguments == null || baseClassTypeParameterIndex >= returnType.TypeArguments.Count)
					return null;
				return returnType.TypeArguments[baseClassTypeParameterIndex];
			}
			foreach (IReturnType baseType in c.BaseTypes) {
				if (baseClass.CompareTo(baseType.GetUnderlyingClass()) == 0) {
					if (baseType.TypeArguments == null || baseClassTypeParameterIndex >= baseType.TypeArguments.Count)
						return null;
					IReturnType result = baseType.TypeArguments[baseClassTypeParameterIndex];
					if (returnType.TypeArguments != null) {
						result = ConstructedReturnType.TranslateType(result, returnType.TypeArguments, false);
					}
					return result;
				}
			}
			return null;
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -