// Unity C# reference source // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.Assemblies; namespace UnityEditor.Experimental.GraphView { // types of port to adapt public class PortSource { } // attribute to declare and adapter public class TypeAdapter : Attribute { } // TODO: This is a straight port from Canvas2D. I don't think that having to check for types in the assembly using reflection is the way we want to go. public class NodeAdapter { private static List s_TypeAdapters; private static Dictionary s_NodeAdapterDictionary; public bool CanAdapt(object a, object b) { if (a == b) return false; // self connections are not permitted if (a == null || b == null) return false; MethodInfo mi = GetAdapter(a, b); if (mi == null) { Debug.Log("adapter node not found for: " + a.GetType() + " -> " + b.GetType()); } return mi != null; } public bool Connect(object a, object b) { MethodInfo mi = GetAdapter(a, b); if (mi == null) { Debug.LogError("Attempt to connect 2 unadaptable types: " + a.GetType() + " -> " + b.GetType()); return false; } object retVal = mi.Invoke(this, new[] { this, a, b }); return (bool)retVal; } IEnumerable GetExtensionMethods(Assembly assembly, Type extendedType) { #pragma warning disable RS0030 // The Banned API Analyzer produces compile errors for any new Linq code. This pre-existing usage has been suppressed, but should be rewritten if possible. #pragma warning disable UA2001 // The Banned API Analyzer produces compile errors for any new Linq code. This pre-existing usage has been suppressed, but should be rewritten if possible. return assembly.GetTypes() #pragma warning restore RS0030 #pragma warning restore UA2001 .Where(t => t.IsSealed && !t.IsGenericType && !t.IsNested) .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) .Where(m => m.IsDefined(typeof(ExtensionAttribute), false) && m.GetParameters()[0].ParameterType == extendedType); } public MethodInfo GetAdapter(object a, object b) { if (a == null || b == null) return null; if (s_NodeAdapterDictionary == null) { s_NodeAdapterDictionary = new Dictionary(); // add extension methods foreach (Assembly assembly in CurrentAssemblies.GetLoadedAssemblies()) { IEnumerable methods; try { methods = GetExtensionMethods(assembly, typeof(NodeAdapter)); } // Invalid DLLs might raise this exception, simply ignore it catch (ReflectionTypeLoadException) { continue; } foreach (MethodInfo method in methods) { ParameterInfo[] methodParams = method.GetParameters(); if (methodParams.Length == 3) { string pa = methodParams[1].ParameterType + methodParams[2].ParameterType.ToString(); int hash = pa.GetHashCode(); if (s_NodeAdapterDictionary.ContainsKey(hash)) { Debug.Log("NodeAdapter: multiple extensions have the same signature:\n" + "1: " + method + "\n" + "2: " + s_NodeAdapterDictionary[hash]); } else { s_NodeAdapterDictionary.Add(hash, method); } } } } } string s = a.GetType().ToString() + b.GetType(); MethodInfo methodInfo; return s_NodeAdapterDictionary.TryGetValue(s.GetHashCode(), out methodInfo) ? methodInfo : null; } public MethodInfo GetTypeAdapter(Type from, Type to) { if (s_TypeAdapters == null) { s_TypeAdapters = new List(); foreach (Assembly assembly in CurrentAssemblies.GetLoadedAssemblies()) { try { foreach (Type temptype in assembly.GetTypes()) { MethodInfo[] methodInfos = temptype.GetMethods(BindingFlags.Public | BindingFlags.Static); foreach (MethodInfo i in methodInfos) { bool hasAttr = i.IsDefined(typeof(TypeAdapter), false); if (hasAttr) { s_TypeAdapters.Add(i); } } } } // Invalid DLLs might raise this exception, simply ignore it catch (ReflectionTypeLoadException) { } catch (Exception ex) { Debug.Log(ex); } } } foreach (MethodInfo i in s_TypeAdapters) { if (i.ReturnType == to) { ParameterInfo[] allParams = i.GetParameters(); if (allParams.Length == 1) { if (allParams[0].ParameterType == from) return i; } } } return null; } } }