/// <summary> /// Gets all objects of type <typeparamref name="T"/> referenced through passed object <paramref name="o"/> /// contained in the lump <paramref name="lumpName"/> stored in this <see cref="BSP"/> class. This is done by /// reflecting the <c>Type</c> of <paramref name="o"/> and looping through its public properties to find /// a member with an <see cref="IndexAttribute"/> attribute and a member with a <see cref="CountAttribute"/> attribute /// both corresponding to <paramref name="lumpName"/>. The index and count are obtained and used to construct /// a new <c>List<<typeparamref name="T"/>></c> object containing the corresponding objects. /// </summary> /// <typeparam name="T">The type of <c>object</c> stored in the lump <paramref name="lumpName"/>.</typeparam> /// <param name="o">The <c>object</c> which contains and index and count corresponding to <paramref name="lumpName"/>.</param> /// <param name="lumpName">The name of the property in this <see cref="BSP"/> object to get a <c>List</c> of objects from.</param> /// <returns>The <c>List<<typeparamref name="T"/>></c> of objects in the lump from the index and length specified in <paramref name="o"/>.</returns> /// <exception cref="ArgumentException">The <see cref="BSP"/> class contains no property corresponding to <paramref name="lumpName"/>.</exception> /// <exception cref="ArgumentException">The <c>object</c> referenced by <paramref name="o"/> is missing one or both members with <c>IndexAttribute</c> or <c>CountAttribute</c> attributes corresponding to <paramref name="lumpName"/>.</exception> /// <exception cref="ArgumentNullException">One or both of <paramref name="o"/> or <paramref name="lumpName"/> is null.</exception> public List <T> GetReferencedObjects <T>(object o, string lumpName) { if (o == null) { throw new ArgumentNullException("Object cannot be null."); } if (lumpName == null) { throw new ArgumentNullException("Lump name cannot be null."); } // First, find the property in this class corresponding to lumpName, and grab its "get" method PropertyInfo targetLump = typeof(BSP).GetProperty(lumpName, BindingFlags.Public | BindingFlags.Instance); if (targetLump == null) { throw new ArgumentException("The lump " + lumpName + " does not exist in the BSP class."); } // Next, find the properties in the passed object corresponding to lumpName, through the Index and Length custom attributes Type objectType = o.GetType(); PropertyInfo[] objectProperties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo indexProperty = null; PropertyInfo countProperty = null; foreach (PropertyInfo info in objectProperties) { IndexAttribute indexAttribute = info.GetCustomAttribute <IndexAttribute>(); if (indexAttribute != null) { if (indexAttribute.lumpName == lumpName) { indexProperty = info; if (indexProperty != null && countProperty != null) { break; } } } CountAttribute lengthAttribute = info.GetCustomAttribute <CountAttribute>(); if (lengthAttribute != null) { if (lengthAttribute.lumpName == lumpName) { countProperty = info; if (indexProperty != null && countProperty != null) { break; } } } } if (indexProperty == null || countProperty == null) { throw new ArgumentException("An object of type " + objectType.Name + " does not implement both an Index and Count for lump " + lumpName + "."); } // Get the index and length from the object int index = (int)(indexProperty.GetGetMethod().Invoke(o, null)); int count = (int)(countProperty.GetGetMethod().Invoke(o, null)); // Get the lump from this class List <T> theLump = targetLump.GetGetMethod().Invoke(this, null) as List <T>; return(theLump.GetRange(index, count)); }
/// <summary> /// Gets all objects of type <typeparamref name="T"/> referenced through passed object <paramref name="o"/> /// contained in the lump <paramref name="lumpName"/> stored in this <see cref="BSP"/> class. This is done by /// reflecting the <c>Type</c> of <paramref name="o"/> and looping through its public properties to find /// a member with an <see cref="IndexAttribute"/> attribute and a member with a <see cref="CountAttribute"/> attribute /// both corresponding to <paramref name="lumpName"/>. The index and count are obtained and used to construct /// a new <c>List<<typeparamref name="T"/>></c> object containing the corresponding objects. /// </summary> /// <typeparam name="T">The type of <c>object</c> stored in the lump <paramref name="lumpName"/>.</typeparam> /// <param name="o">The <c>object</c> which contains and index and count corresponding to <paramref name="lumpName"/>.</param> /// <param name="lumpName">The name of the property in this <see cref="BSP"/> object to get a <c>List</c> of objects from.</param> /// <returns>The <c>List<<typeparamref name="T"/>></c> of objects in the lump from the index and length specified in <paramref name="o"/>.</returns> /// <exception cref="ArgumentException">The <see cref="BSP"/> class contains no property corresponding to <paramref name="lumpName"/>.</exception> /// <exception cref="ArgumentException">The <c>object</c> referenced by <paramref name="o"/> is missing one or both members with <c>IndexAttribute</c> or <c>CountAttribute</c> attributes corresponding to <paramref name="lumpName"/>.</exception> /// <exception cref="ArgumentNullException">One or both of <paramref name="o"/> or <paramref name="lumpName"/> is null.</exception> public List <T> GetReferencedObjects <T>(object o, string lumpName) { if (o == null) { throw new ArgumentNullException("Object cannot be null."); } if (lumpName == null) { throw new ArgumentNullException("Lump name cannot be null."); } // First, find the property in this class corresponding to lumpName, and grab its "get" method PropertyInfo targetLump = typeof(BSP).GetProperty(lumpName, BindingFlags.Public | BindingFlags.Instance); if (targetLump == null) { throw new ArgumentException("The lump " + lumpName + " does not exist in the BSP class."); } // Next, find the properties in the passed object corresponding to lumpName, through the Index and Length custom attributes Type objectType = o.GetType(); PropertyInfo[] objectProperties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo indexProperty = null; PropertyInfo countProperty = null; foreach (PropertyInfo info in objectProperties) { IndexAttribute indexAttribute = info.GetCustomAttribute <IndexAttribute>(); if (indexAttribute != null) { if (indexAttribute.lumpName == lumpName) { indexProperty = info; if (indexProperty != null && countProperty != null) { break; } } } CountAttribute lengthAttribute = info.GetCustomAttribute <CountAttribute>(); if (lengthAttribute != null) { if (lengthAttribute.lumpName == lumpName) { countProperty = info; if (indexProperty != null && countProperty != null) { break; } } } } if (indexProperty == null || countProperty == null) { throw new ArgumentException("An object of type " + objectType.Name + " does not implement both an Index and Count for lump " + lumpName + "."); } // Get the index and length from the object int index = (int)(indexProperty.GetGetMethod().Invoke(o, null)); int count = (int)(countProperty.GetGetMethod().Invoke(o, null)); // Get the lump from this class IList <T> theLump = targetLump.GetGetMethod().Invoke(this, null) as IList <T>; // Copy items from the lump into a return list. // IList<T> lacks AddRange and this is faster and creates less garbage than any Linq trickery I could come up with. // Passing references to IList<T> out of this method just eats obscene amounts of memory until the system runs out. List <T> ret = new List <T>(count); for (int i = 0; i < count; ++i) { ret.Add(theLump[index + i]); } return(ret); }