private static void DoInit() { DoValidateTypes(); List <ClassEntry> exports = new List <ClassEntry>(); foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type type in assembly.GetTypes()) { ExportClassAttribute attr = Attribute.GetCustomAttribute(type, typeof(ExportClassAttribute), false) as ExportClassAttribute; if (attr != null) { exports.Add(new ClassEntry(type, attr)); } RegisterAttribute attr2 = Attribute.GetCustomAttribute(type, typeof(RegisterAttribute), false) as RegisterAttribute; if (attr2 != null) { string name = attr2.Name ?? type.Name; if (type.IsValueType) { TypeEncoder.Register(type, name); } else { NSObject.Register(type, name); } } } } for (int i = 0; i < exports.Count; ++i) // must process base types before derived types { for (int j = i + 1; j < exports.Count; ++j) // crappy O(N^2) sort, but it's difficult to use a more efficient sort because we cannot meaningfully compare two elements in isolation { // should be OK though, because this is only for exported types, not registered types if (ClassEntry.LeftDerivesFromRight(exports[i], exports[j])) { ClassEntry temp = exports[i]; exports[i] = exports[j]; exports[j] = temp; } } } foreach (ClassEntry export in exports) { if (ms_typeNames.ContainsKey(export.Attr.DerivedName)) { throw new ArgumentException(string.Format("{0} exports {1} but that class name has already been exported.", export.Type, export.Attr.DerivedName)); } ms_typeNames.Add(export.Attr.DerivedName, export.Type); ms_classNames.Add(export.Type, export.Attr.DerivedName); DoInitClass(export.Attr.DerivedName, export.Attr.BaseName, export.Type, export.Attr.Outlets); } }
public ClassEntry(Type type, ExportClassAttribute attr) { Type = type; Attr = attr; ExportClassAttribute baseAttr = Attribute.GetCustomAttribute(type.BaseType, typeof(ExportClassAttribute), false) as ExportClassAttribute; if (baseAttr != null) { Base = new ClassEntry(type.BaseType, baseAttr); } }
private static void DoValidateType(Type type) { foreach (MethodInfo info in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)) { ExportClassAttribute attr = Attribute.GetCustomAttribute(type, typeof(ExportClassAttribute), false) as ExportClassAttribute; if (attr != null) { if (!typeof(NSObject).IsAssignableFrom(type)) { throw new ArgumentException(string.Format("{0} uses ExportClassAttribute, but does not descend from NSObject.", type)); } } DoValidateMethod(type, info); } }
private static void DoValidateMethod(Type type, MethodInfo info) { ExportClassAttribute klassAttr = Attribute.GetCustomAttribute(type, typeof(ExportClassAttribute), false) as ExportClassAttribute; RegisterAttribute methodAttr = Attribute.GetCustomAttribute(info, typeof(RegisterAttribute), false) as RegisterAttribute; if (klassAttr != null) { } else { if (methodAttr != null) { throw new ArgumentException(string.Format("{0} uses RegisterAttribute, but not ExportClassAttribute.", type)); } } }
/// <summary>Constructs a managed object which is associated with an unmanaged object.</summary> /// <remarks>In general multiple NSObject instances can be associated with the same unmanaged object. /// The exception is that only one <see cref = "ExportClassAttribute">ExportClassAttribute</see> object can be associated with an /// unmanaged object. If an attempt is made to construct two NSObjects pointing to the same /// exported object an exception will be thrown. (The reason for this is that exported instances may /// have managed state which should be associated with one and only one unmanaged instance).</remarks> public NSObject(IntPtr instance) { m_instance = instance; // note that it's legal to send messages to nil m_class = IntPtr.Zero; if (m_instance != IntPtr.Zero) { // It's a little inefficient to always grab this information, but it makes // dumping objects much easier because we can safely do it even when ref // counts are zero. IntPtr exception = IntPtr.Zero; m_class = DirectCalls.Callp(m_instance, Selector.Class, ref exception); if (exception != IntPtr.Zero) { CocoaException.Raise(exception); } m_baseClass = DirectCalls.Callp(m_class, Selector.SuperClass, ref exception); if (exception != IntPtr.Zero) { CocoaException.Raise(exception); } #if DEBUG if (SaveStackTraces) { var stack = new System.Diagnostics.StackTrace(1); StackTrace = new string[stack.FrameCount]; for (int i = 0; i < stack.FrameCount; ++i) // TODO: provide a MaxStackDepth method? { StackFrame frame = stack.GetFrame(i); if (!string.IsNullOrEmpty(frame.GetFileName())) { StackTrace[i] = string.Format("{0}|{1} {2}:{3}", frame.GetMethod().DeclaringType, frame.GetMethod(), frame.GetFileName(), frame.GetFileLineNumber()); } else { StackTrace[i] = string.Format("{0}|{1}", frame.GetMethod().DeclaringType, frame.GetMethod()); } } } #endif lock (ms_instancesLock) { bool exported; Type type = GetType(); if (!ms_exports.TryGetValue(type, out exported)) // GetCustomAttribute turns out to be very slow { ExportClassAttribute attr = Attribute.GetCustomAttribute(type, typeof(ExportClassAttribute)) as ExportClassAttribute; exported = attr != null; ms_exports.Add(type, exported); } if (exported) { if (ms_instances.ContainsKey(instance)) { throw new InvalidOperationException(type + " is being constructed twice with the same id, try using the Lookup method."); } ms_instances.Add(instance, this); } } #if DEBUG ms_refs.Add(this); #endif } }