-
Notifications
You must be signed in to change notification settings - Fork 414
assembly.FullName.Contains ("Assembly") not working with Assembly Definition File #159
Comments
Removing all the .Where() will results in insane amount of GC.
|
Ya, makes sense. Will see what you come up with, thanks! |
Any news? Otherwise, at it is quite an edge-case, I would say you would indeed need to edit the code at that point... |
I think this issue should remain open so someone can take a look at it in the future. I don't think this is an edge-case. Custom assemblies are very much in use with Unity. A good start here is to ignore all assemblies with names starting with Unity. (Llot's of new packages use names like Unity.someComponent), UnityEngine. and UnityEditor. (all including the dot). For newer .net, we also could ignore assemblies that are dynamic (check against Assembly.IsDynamic). This will probably reduce the pressure by a lot. As a last measure, if this is called more than once per type (I didn't study the code yet), it can be cached to a Dictionary<Type, Type[]> to improve query performance even further, at the cost of some memory. |
Yeah, I have working code, which is basically a whitelist string array and some
List<Type> and List<MethodInfo> for all the stuff that need reflection in
NodeEditorFramework, and use static constructor and [InitializeOnLoad] attribute to
achieve best experience... not elegant enough though.
I will post the code after my project deadline.
|
Also I don't consider this a edge-class either due to Assembly Definition Files is a major feature after 2017 version (in my opinion). |
Alright, alright:) |
This suddenly comes to my mind. using UnityEngine;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
namespace NodeEditorFramework.Utilities
{
public static class ReflectionUtility
{
public static string[] assemblyFilters = new string[3] { "Story", "NodeEditor" };
static readonly Assembly[] currentDomainAssembliesCache;
public static Assembly[] CurrentDomainAssembliesCache
{
get { return currentDomainAssembliesCache; }
}
static readonly List<Type> nodeTypes;
public static List<Type> NodeTypes { get { return nodeTypes; }}
static readonly List<Type> nodeCanvasTypes;
public static List<Type> NodeCanvasTypes { get { return nodeCanvasTypes; }}
static readonly List<Type> connectionPortStyleTypes;
public static List<Type> ConnectionPortStyleTypes { get { return connectionPortStyleTypes; }}
static readonly List<Type> importExportType;
public static List<Type> ImportExportType { get { return importExportType; }}
static readonly List<MethodInfo> usedByInputSystem;
public static List<MethodInfo> UsedByInputSystem { get { return usedByInputSystem; }}
static ReflectionUtility ()
{
DateTime time = DateTime.Now;
currentDomainAssembliesCache = AppDomain.CurrentDomain.GetAssemblies().Where(a => assemblyFilters.Any(f => a.FullName.Contains(f))).ToArray();
// Debug.Log("GetAssemblies:" + (DateTime.Now - time).TotalMilliseconds + "ms");
nodeTypes = new List<Type>(50);
nodeCanvasTypes = new List<Type>(10);
connectionPortStyleTypes = new List<Type>(10);
importExportType = new List<Type>(3);
usedByInputSystem = new List<MethodInfo>(50);
foreach (Assembly assembly in currentDomainAssembliesCache)
{
time = DateTime.Now;
foreach (Type type in assembly.GetTypes())
{
if (IsValidType<Node>(type)) nodeTypes.Add(type);
if (IsValidType<NodeCanvas>(type, typeof(NodeCanvasTypeAttribute))) nodeCanvasTypes.Add(type);
if (IsValidType<ConnectionPortStyle>(type)) connectionPortStyleTypes.Add(type);
if (IsValidType<NodeEditorFramework.IO.ImportExportFormat>(type)) importExportType.Add(type);
foreach (MethodInfo method in type.GetMethods (BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
{
if (method.GetCustomAttributes(true).Any(t => t.GetType() == typeof(EventHandlerAttribute) || t.GetType() == typeof(HotkeyAttribute) || t.GetType() == typeof(ContextEntryAttribute) || t.GetType() == typeof(ContextFillerAttribute))) usedByInputSystem.Add(method);
}
}
// Debug.Log("Types in assembly " + assembly.FullName + ":" + (DateTime.Now - time).TotalMilliseconds + "ms");
}
}
public class ReflectionSearchIgnoreAttribute : Attribute
{
public ReflectionSearchIgnoreAttribute () { }
}
static bool IsValidType<T> (Type type, Type hasAttr = null)
{
if (type.IsClass
&& !type.IsAbstract
&& type.IsSubclassOf(typeof(T))
&& ((hasAttr == null)? true : (type.GetCustomAttributes (hasAttr, false).Length > 0))
&& !(type.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Length > 0))
return true;
else return false;
}
/// <summary>
/// Gets all non-abstract types extending the given base type
/// </summary>
public static Type[] getSubTypes (Type baseType)
{
return CurrentDomainAssembliesCache
.SelectMany ((Assembly assembly) => assembly.GetTypes ()
.Where ((Type T) =>
(T.IsClass && !T.IsAbstract)
&& T.IsSubclassOf (baseType)
&& !T.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Any ())
).ToArray ();
}
/// <summary>
/// Gets all non-abstract types extending the given base type and with the given attribute
/// </summary>
public static Type[] getSubTypes (Type baseType, Type hasAttribute)
{
return CurrentDomainAssembliesCache
.SelectMany ((Assembly assembly) => assembly.GetTypes ()
.Where ((Type T) =>
(T.IsClass && !T.IsAbstract)
&& T.IsSubclassOf (baseType)
&& T.GetCustomAttributes (hasAttribute, false).Any ()
&& !T.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Any ())
).ToArray ();
}
/// <summary>
/// Returns all fields that should be serialized in the given type
/// </summary>
public static FieldInfo[] getSerializedFields (Type type)
{
return type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where ((FieldInfo field) =>
(field.IsPublic && !field.GetCustomAttributes (typeof(NonSerializedAttribute), true).Any ())
|| field.GetCustomAttributes (typeof(SerializeField), true).Any ()
&& !field.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Any ())
.ToArray ();
}
/// <summary>
/// Returns all fields that should be serialized in the given type, minus the fields declared in or above the given base type
/// </summary>
public static FieldInfo[] getSerializedFields (Type type, Type hiddenBaseType)
{
return type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where ((FieldInfo field) =>
(hiddenBaseType == null || !field.DeclaringType.IsAssignableFrom (hiddenBaseType))
&& ((field.IsPublic && !field.GetCustomAttributes (typeof(NonSerializedAttribute), true).Any ())
|| field.GetCustomAttributes (typeof(SerializeField), true).Any ()
&& !field.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Any ()))
.ToArray ();
}
/// <summary>
/// Gets all fields in the classType of the specified fieldType
/// </summary>
public static FieldInfo[] getFieldsOfType (Type classType, Type fieldType)
{
return classType.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where ((FieldInfo field) =>
field.FieldType == fieldType || field.FieldType.IsSubclassOf (fieldType)
&& !field.GetCustomAttributes (typeof(ReflectionSearchIgnoreAttribute), false).Any ())
.ToArray ();
}
}
} |
Assembly Definition File create assembly dll file with custom name.
The text was updated successfully, but these errors were encountered: