📄 delegate.cs
字号:
//// delegate.cs: Delegate Handler//// Authors:// Ravi Pratap (ravi@ximian.com)// Miguel de Icaza (miguel@ximian.com)//// Licensed under the terms of the GNU GPL//// (C) 2001 Ximian, Inc (http://www.ximian.com)////using System;using System.Collections;using System.Reflection;using System.Reflection.Emit;using System.Text;namespace Mono.CSharp { /// <summary> /// Holds Delegates /// </summary> public class Delegate : DeclSpace { public Expression ReturnType; public Parameters Parameters; public ConstructorBuilder ConstructorBuilder; public MethodBuilder InvokeBuilder; public MethodBuilder BeginInvokeBuilder; public MethodBuilder EndInvokeBuilder; Type [] param_types; Type ret_type; static string[] attribute_targets = new string [] { "type", "return" }; Expression instance_expr; MethodBase delegate_method; ReturnParameter return_attributes; const int AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.UNSAFE | Modifiers.PRIVATE; public Delegate (NamespaceEntry ns, TypeContainer parent, Expression type, int mod_flags, MemberName name, Parameters param_list, Attributes attrs) : base (ns, parent, name, attrs) { this.ReturnType = type; ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, name.Location); Parameters = param_list; } public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) { if (a.Target == AttributeTargets.ReturnValue) { if (return_attributes == null) return_attributes = new ReturnParameter (InvokeBuilder, Location); return_attributes.ApplyAttributeBuilder (a, cb); return; } base.ApplyAttributeBuilder (a, cb); } public override TypeBuilder DefineType () { if (TypeBuilder != null) return TypeBuilder; ec = new EmitContext (this, this, Location, null, null, ModFlags, false); if (TypeManager.multicast_delegate_type == null && !RootContext.StdLib) { Namespace system = RootNamespace.Global.GetNamespace ("System", true); TypeExpr expr = system.Lookup (this, "MulticastDelegate", Location) as TypeExpr; TypeManager.multicast_delegate_type = expr.ResolveType (ec); } if (TypeManager.multicast_delegate_type == null) throw new InternalErrorException ("System.MulticastDelegate unresolved"); if (IsTopLevel) { if (TypeManager.NamespaceClash (Name, Location)) return null; ModuleBuilder builder = CodeGen.Module.Builder; TypeBuilder = builder.DefineType ( Name, TypeAttr, TypeManager.multicast_delegate_type); } else { TypeBuilder builder = Parent.TypeBuilder; string name = Name.Substring (1 + Name.LastIndexOf ('.')); TypeBuilder = builder.DefineNestedType ( name, TypeAttr, TypeManager.multicast_delegate_type); } TypeManager.AddUserType (this); return TypeBuilder; } public override bool Define () { MethodAttributes mattr; int i; if (ec == null) throw new InternalErrorException ("Define called before DefineType?"); // FIXME: POSSIBLY make this static, as it is always constant // Type [] const_arg_types = new Type [2]; const_arg_types [0] = TypeManager.object_type; const_arg_types [1] = TypeManager.intptr_type; mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; ConstructorBuilder = TypeBuilder.DefineConstructor (mattr, CallingConventions.Standard, const_arg_types); ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object"); ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method"); // // HACK because System.Reflection.Emit is lame // Parameter [] fixed_pars = new Parameter [2]; fixed_pars [0] = new Parameter (TypeManager.system_object_expr, "object", Parameter.Modifier.NONE, null, Location); fixed_pars [1] = new Parameter (TypeManager.system_intptr_expr, "method", Parameter.Modifier.NONE, null, Location); Parameters const_parameters = new Parameters (fixed_pars, null); TypeManager.RegisterMethod ( ConstructorBuilder, new InternalParameters (const_arg_types, const_parameters), const_arg_types); ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); // // Here the various methods like Invoke, BeginInvoke etc are defined // // First, call the `out of band' special method for // defining recursively any types we need: param_types = Parameters.GetParameterInfo (ec); if (param_types == null) return false; // // Invoke method // // Check accessibility foreach (Type partype in param_types){ if (!Parent.AsAccessible (partype, ModFlags)) { Report.Error (59, Location, "Inconsistent accessibility: parameter type `" + TypeManager.CSharpName (partype) + "' is less " + "accessible than delegate `" + Name + "'"); return false; } if (partype.IsPointer && !UnsafeOK (Parent)) return false; } ReturnType = ReturnType.ResolveAsTypeTerminal (ec, false); if (ReturnType == null) return false; ret_type = ReturnType.Type; if (ret_type == null) return false; CheckObsoleteType (ReturnType); if (!Parent.AsAccessible (ret_type, ModFlags)) { Report.Error (58, Location, "Inconsistent accessibility: return type `" + TypeManager.CSharpName (ret_type) + "' is less " + "accessible than delegate `" + Name + "'"); return false; } if (ret_type.IsPointer && !UnsafeOK (Parent)) return false; if (RootContext.StdLib && (ret_type == TypeManager.arg_iterator_type || ret_type == TypeManager.typed_reference_type)) { Method.Error1599 (Location, ret_type); return false; } // // We don't have to check any others because they are all // guaranteed to be accessible - they are standard types. // CallingConventions cc = Parameters.GetCallingConvention (); mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; InvokeBuilder = TypeBuilder.DefineMethod ("Invoke", mattr, cc, ret_type, param_types); // // Define parameters, and count out/ref parameters // int out_params = 0; i = 0; if (Parameters.FixedParameters != null){ int top = Parameters.FixedParameters.Length; Parameter p; for (; i < top; i++) { p = Parameters.FixedParameters [i]; p.DefineParameter (ec, InvokeBuilder, null, i + 1); if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0) out_params++; } } if (Parameters.ArrayParameter != null){ if (TypeManager.param_array_type == null && !RootContext.StdLib) { Namespace system = RootNamespace.Global.GetNamespace ("System", true); TypeExpr expr = system.Lookup (this, "ParamArrayAttribute", Location) as TypeExpr; TypeManager.param_array_type = expr.ResolveType (ec); } if (TypeManager.cons_param_array_attribute == null) { Type [] void_arg = { }; TypeManager.cons_param_array_attribute = TypeManager.GetConstructor ( TypeManager.param_array_type, void_arg); } ParameterBuilder pb = InvokeBuilder.DefineParameter ( i + 1, Parameters.ArrayParameter.Attributes,Parameters.ArrayParameter.Name); pb.SetCustomAttribute ( new CustomAttributeBuilder (TypeManager.cons_param_array_attribute, new object [0])); } InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); TypeManager.RegisterMethod (InvokeBuilder, new InternalParameters (param_types, Parameters), param_types); // // BeginInvoke // int params_num = param_types.Length; Type [] async_param_types = new Type [params_num + 2]; param_types.CopyTo (async_param_types, 0); async_param_types [params_num] = TypeManager.asynccallback_type; async_param_types [params_num + 1] = TypeManager.object_type; mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke", mattr, cc, TypeManager.iasyncresult_type, async_param_types); i = 0; if (Parameters.FixedParameters != null){ int top = Parameters.FixedParameters.Length; Parameter p; for (i = 0 ; i < top; i++) { p = Parameters.FixedParameters [i]; p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1); } } if (Parameters.ArrayParameter != null){ Parameter p = Parameters.ArrayParameter; p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1); i++; } BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback"); BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object"); BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); Parameter [] async_params = new Parameter [params_num + 2]; int n = 0; if (Parameters.FixedParameters != null){ Parameters.FixedParameters.CopyTo (async_params, 0); n = Parameters.FixedParameters.Length; } if (Parameters.ArrayParameter != null) async_params [n] = Parameters.ArrayParameter; async_params [params_num] = new Parameter ( TypeManager.system_asynccallback_expr, "callback", Parameter.Modifier.NONE, null, Location); async_params [params_num + 1] = new Parameter ( TypeManager.system_object_expr, "object", Parameter.Modifier.NONE, null, Location); Parameters async_parameters = new Parameters (async_params, null); TypeManager.RegisterMethod (BeginInvokeBuilder, new InternalParameters (async_parameters.GetParameterInfo (ec), async_parameters), async_param_types); // // EndInvoke is a bit more interesting, all the parameters labeled as // out or ref have to be duplicated here. // Type [] end_param_types = new Type [out_params + 1]; Parameter [] end_params = new Parameter [out_params + 1]; int param = 0; if (out_params > 0){ int top = Parameters.FixedParameters.Length; for (i = 0; i < top; i++){ Parameter p = Parameters.FixedParameters [i]; if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0) continue; end_param_types [param] = param_types [i]; end_params [param] = p; param++; } } end_param_types [out_params] = TypeManager.iasyncresult_type; end_params [out_params] = new Parameter (TypeManager.system_iasyncresult_expr, "result", Parameter.Modifier.NONE, null, Location); // // Create method, define parameters, register parameters with type system // EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_param_types); EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); // // EndInvoke: Label the parameters // EndInvokeBuilder.DefineParameter (out_params + 1, ParameterAttributes.None, "result"); for (i = 0; i < end_params.Length-1; i++){ EndInvokeBuilder.DefineParameter (i + 1, end_params [i].Attributes, end_params [i].Name); } Parameters end_parameters = new Parameters (end_params, null); TypeManager.RegisterMethod ( EndInvokeBuilder, new InternalParameters (end_parameters.GetParameterInfo (ec), end_parameters), end_param_types); return true; } public override void Emit () { if (OptAttributes != null) { Parameters.LabelParameters (ec, InvokeBuilder); OptAttributes.Emit (ec, this); } base.Emit (); } protected override TypeAttributes TypeAttr { get { return Modifiers.TypeAttr (ModFlags, IsTopLevel) | TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr; } } public override string[] ValidAttributeTargets { get { return attribute_targets; } } //TODO: duplicate protected override bool VerifyClsCompliance (DeclSpace ds) { if (!base.VerifyClsCompliance (ds)) { return false; } AttributeTester.AreParametersCompliant (Parameters.FixedParameters, Location); if (!AttributeTester.IsClsCompliant (ReturnType.Type)) { Report.Error (3002, Location, "Return type of `{0}' is not CLS-compliant", GetSignatureForError ()); } return true; } // // Returns the MethodBase for "Invoke" from a delegate type, this is used // to extract the signature of a delegate. // public static MethodInfo GetInvokeMethod (EmitContext ec, Type delegate_type, Location loc) { Expression ml = Expression.MemberLookup ( ec, delegate_type, "Invoke", loc); if (!(ml is MethodGroupExpr)) { Report.Error (-100, loc, "Internal error: could not find Invoke method!"); return null; } return (MethodInfo) (((MethodGroupExpr) ml).Methods [0]); } /// <summary> /// Verifies whether the method in question is compatible with the delegate /// Returns the method itself if okay and null if not. /// </summary> public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb, Location loc) { ParameterData pd = TypeManager.GetParameterData (mb); int pd_count = pd.Count; MethodBase invoke_mb = GetInvokeMethod (ec, delegate_type, loc); if (invoke_mb == null) return null; ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb); if (invoke_pd.Count != pd_count) return null; for (int i = pd_count; i > 0; ) { i--; Type invoke_pd_type = invoke_pd.ParameterType (i); Type pd_type = pd.ParameterType (i); Parameter.Modifier invoke_pd_type_mod = invoke_pd.ParameterModifier (i); Parameter.Modifier pd_type_mod = pd.ParameterModifier (i); if (invoke_pd_type == pd_type && invoke_pd_type_mod == pd_type_mod) continue; if (invoke_pd_type.IsSubclassOf (pd_type) && invoke_pd_type_mod == pd_type_mod) if (RootContext.Version == LanguageVersion.ISO_1) { Report.FeatureIsNotStandardized (loc, "contravariance"); return null; } else continue; return null; } Type invoke_mb_retval = ((MethodInfo) invoke_mb).ReturnType; Type mb_retval = ((MethodInfo) mb).ReturnType; if (invoke_mb_retval == mb_retval) return mb; if (mb_retval.IsSubclassOf (invoke_mb_retval)) if (RootContext.Version == LanguageVersion.ISO_1) { Report.FeatureIsNotStandardized (loc, "covariance"); return null; } else return mb; return null; } // <summary> // Verifies whether the invocation arguments are compatible with the // delegate's target method // </summary> public static bool VerifyApplicability (EmitContext ec, Type delegate_type, ArrayList args, Location loc) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -