📄 class.cs
字号:
//// class.cs: Class and Struct handlers//// Authors: Miguel de Icaza (miguel@gnu.org)// Martin Baulig (martin@ximian.com)// Marek Safar (marek.safar@seznam.cz)//// Licensed under the terms of the GNU GPL//// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)// (C) 2004 Novell, Inc////// 2002-10-11 Miguel de Icaza <miguel@ximian.com>//// * class.cs: Following the comment from 2002-09-26 to AddMethod, I// have fixed a remaining problem: not every AddXXXX was adding a// fully qualified name. //// Now everyone registers a fully qualified name in the DeclSpace as// being defined instead of the partial name. //// Downsides: we are slower than we need to be due to the excess// copies and the names being registered this way. //// The reason for this is that we currently depend (on the corlib// bootstrap for instance) that types are fully qualified, because// we dump all the types in the namespace, and we should really have// types inserted into the proper namespace, so we can only store the// basenames in the defined_names array.////#define CACHEusing System;using System.Collections;using System.Collections.Specialized;using System.Reflection;using System.Reflection.Emit;using System.Runtime.CompilerServices;using System.Runtime.InteropServices;using System.Security;using System.Security.Permissions;using System.Text;#if BOOTSTRAP_WITH_OLDLIBusing XmlElement = System.Object;#elseusing System.Xml;#endifusing Mono.CompilerServices.SymbolWriter;namespace Mono.CSharp { public enum Kind { Root, Struct, Class, Interface } /// <summary> /// This is the base class for structs and classes. /// </summary> public abstract class TypeContainer : DeclSpace, IMemberContainer { public class MemberCoreArrayList: ArrayList { /// <summary> /// Defines the MemberCore objects that are in this array /// </summary> public virtual void DefineContainerMembers () { foreach (MemberCore mc in this) { mc.Define (); } } public virtual void Emit () { foreach (MemberCore mc in this) mc.Emit (); } } public class MethodArrayList : MemberCoreArrayList { [Flags] enum CachedMethods { Equals = 1, GetHashCode = 1 << 1 } CachedMethods cached_method; TypeContainer container; public MethodArrayList (TypeContainer container) { this.container = container; } /// <summary> /// Method container contains Equals method /// </summary> public bool HasEquals { set { cached_method |= CachedMethods.Equals; } get { return (cached_method & CachedMethods.Equals) != 0; } } /// <summary> /// Method container contains GetHashCode method /// </summary> public bool HasGetHashCode { set { cached_method |= CachedMethods.GetHashCode; } get { return (cached_method & CachedMethods.GetHashCode) != 0; } } public override void DefineContainerMembers () { base.DefineContainerMembers (); if ((RootContext.WarningLevel >= 3) && HasEquals && !HasGetHashCode) { Report.Warning (659, container.Location, "`{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()", container.GetSignatureForError ()); } } } public sealed class IndexerArrayList : MemberCoreArrayList { /// <summary> /// The indexer name for this container /// </summary> public string IndexerName = DefaultIndexerName; bool seen_normal_indexers = false; TypeContainer container; public IndexerArrayList (TypeContainer container) { this.container = container; } /// <summary> /// Defines the indexers, and also verifies that the IndexerNameAttribute in the /// class is consistent. Either it is `Item' or it is the name defined by all the /// indexers with the `IndexerName' attribute. /// /// Turns out that the IndexerNameAttribute is applied to each indexer, /// but it is never emitted, instead a DefaultMember attribute is attached /// to the class. /// </summary> public override void DefineContainerMembers() { base.DefineContainerMembers (); string class_indexer_name = null; // // If there's both an explicit and an implicit interface implementation, the // explicit one actually implements the interface while the other one is just // a normal indexer. See bug #37714. // // Invariant maintained by AddIndexer(): All explicit interface indexers precede normal indexers foreach (Indexer i in this) { if (i.InterfaceType != null) { if (seen_normal_indexers) throw new Exception ("Internal Error: 'Indexers' array not sorted properly."); continue; } seen_normal_indexers = true; if (class_indexer_name == null) { class_indexer_name = i.ShortName; continue; } if (i.ShortName != class_indexer_name) Report.Error (668, i.Location, "Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type"); } if (class_indexer_name != null) IndexerName = class_indexer_name; } public override void Emit () { base.Emit (); if (!seen_normal_indexers) return; CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.default_member_ctor, new string [] { IndexerName }); container.TypeBuilder.SetCustomAttribute (cb); } } public class OperatorArrayList: MemberCoreArrayList { TypeContainer container; public OperatorArrayList (TypeContainer container) { this.container = container; } // // Operator pair checking // class OperatorEntry { public int flags; public Type ret_type; public Type type1, type2; public Operator op; public Operator.OpType ot; public OperatorEntry (int f, Operator o) { flags = f; ret_type = o.OperatorMethod.ReturnType; Type [] pt = o.OperatorMethod.ParameterTypes; type1 = pt [0]; type2 = pt [1]; op = o; ot = o.OperatorType; } public override int GetHashCode () { return ret_type.GetHashCode (); } public override bool Equals (object o) { OperatorEntry other = (OperatorEntry) o; if (other.ret_type != ret_type) return false; if (other.type1 != type1) return false; if (other.type2 != type2) return false; return true; } } // // Checks that some operators come in pairs: // == and != // > and < // >= and <= // true and false // // They are matched based on the return type and the argument types // void CheckPairedOperators () { IDictionary pairs = new HybridDictionary (); Operator true_op = null; Operator false_op = null; bool has_equality_or_inequality = false; // Register all the operators we care about. foreach (Operator op in this){ int reg = 0; // Skip erroneous code. if (op.OperatorMethod == null) continue; switch (op.OperatorType){ case Operator.OpType.Equality: reg = 1; has_equality_or_inequality = true; break; case Operator.OpType.Inequality: reg = 2; has_equality_or_inequality = true; break; case Operator.OpType.True: true_op = op; break; case Operator.OpType.False: false_op = op; break; case Operator.OpType.GreaterThan: reg = 1; break; case Operator.OpType.LessThan: reg = 2; break; case Operator.OpType.GreaterThanOrEqual: reg = 1; break; case Operator.OpType.LessThanOrEqual: reg = 2; break; } if (reg == 0) continue; OperatorEntry oe = new OperatorEntry (reg, op); object o = pairs [oe]; if (o == null) pairs [oe] = oe; else { oe = (OperatorEntry) o; oe.flags |= reg; } } if (true_op != null){ if (false_op == null) Report.Error (216, true_op.Location, "The operator `{0}' requires a matching operator `false' to also be defined", true_op.GetSignatureForError ()); } else if (false_op != null) Report.Error (216, false_op.Location, "The operator `{0}' requires a matching operator `true' to also be defined", false_op.GetSignatureForError ()); // // Look for the mistakes. // foreach (DictionaryEntry de in pairs){ OperatorEntry oe = (OperatorEntry) de.Key; if (oe.flags == 3) continue; string s = ""; switch (oe.ot){ case Operator.OpType.Equality: s = "!="; break; case Operator.OpType.Inequality: s = "=="; break; case Operator.OpType.GreaterThan: s = "<"; break; case Operator.OpType.LessThan: s = ">"; break; case Operator.OpType.GreaterThanOrEqual: s = "<="; break; case Operator.OpType.LessThanOrEqual: s = ">="; break; } Report.Error (216, oe.op.Location, "The operator `{0}' requires a matching operator `{1}' to also be defined", oe.op.GetSignatureForError (), s); } if (has_equality_or_inequality && (RootContext.WarningLevel > 2)) { if (container.Methods == null || !container.Methods.HasEquals) Report.Warning (660, container.Location, "`{0}' defines operator == or operator != but does not override Object.Equals(object o)", container.GetSignatureForError ()); if (container.Methods == null || !container.Methods.HasGetHashCode) Report.Warning (661, container.Location, "`{0}' defines operator == or operator != but does not override Object.GetHashCode()", container.GetSignatureForError ()); } } public override void DefineContainerMembers () { base.DefineContainerMembers (); CheckPairedOperators (); } } // Whether this is a struct, class or interface public readonly Kind Kind; // Holds a list of classes and structures ArrayList types; // Holds the list of properties MemberCoreArrayList properties; // Holds the list of enumerations MemberCoreArrayList enums; // Holds the list of delegates MemberCoreArrayList delegates; // Holds the list of constructors protected MemberCoreArrayList instance_constructors; // Holds the list of fields MemberCoreArrayList fields; // Holds a list of fields that have initializers protected ArrayList initialized_fields; // Holds a list of static fields that have initializers protected ArrayList initialized_static_fields; // Holds the list of constants MemberCoreArrayList constants; // Holds the list of MemberCoreArrayList interfaces; // Holds the methods. MethodArrayList methods; // Holds the events protected MemberCoreArrayList events; // Holds the indexers IndexerArrayList indexers; // Holds the operators MemberCoreArrayList operators; // Holds the iterators ArrayList iterators; // Holds the parts of a partial class; ArrayList parts; // // Pointers to the default constructor and the default static constructor // protected Constructor default_constructor; protected Constructor default_static_constructor; // // Points to the first non-static field added to the container. // // This is an arbitrary choice. We are interested in looking at _some_ non-static field, // and the first one's as good as any. // FieldBase first_nonstatic_field = null; // // This one is computed after we can distinguish interfaces // from classes from the arraylist `type_bases' // string base_class_name; TypeExpr base_type; TypeExpr[] iface_exprs; ArrayList type_bases; bool members_defined; bool members_defined_ok; // The interfaces we implement. protected Type[] ifaces; protected Type ptype; // The base member cache and our member cache MemberCache base_cache; MemberCache member_cache; public const string DefaultIndexerName = "Item"; public TypeContainer (NamespaceEntry ns, TypeContainer parent, MemberName name, Attributes attrs, Kind kind) : base (ns, parent, name, attrs) { if (parent != null && parent != RootContext.Tree.Types && parent.NamespaceEntry != ns) throw new InternalErrorException ("A nested type should be in the same NamespaceEntry as its enclosing class"); this.Kind = kind; types = new ArrayList (); base_class_name = null; } public bool AddToMemberContainer (MemberCore symbol) { return AddToContainer (symbol, symbol.Name); } protected virtual bool AddToTypeContainer (DeclSpace ds) { return AddToContainer (ds, ds.Basename); } public void AddConstant (Const constant) { if (!AddToMemberContainer (constant)) return; if (constants == null) constants = new MemberCoreArrayList (); constants.Add (constant); } public void AddEnum (Mono.CSharp.Enum e) { if (!AddToTypeContainer (e)) return; if (enums == null) enums = new MemberCoreArrayList (); enums.Add (e); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -