You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ReflectionHelper.cs 3.6 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // ReflectionHelper.cs
  3. using System.Reflection;
  4. using Google.Protobuf;
  5. using Google.Protobuf.Reflection;
  6. using Microsoft.AutoGen.Contracts;
  7. using Microsoft.AutoGen.Core;
  8. namespace Microsoft.AutoGen.RuntimeGateway.Grpc.Tests;
  9. public sealed class ReflectionHelper
  10. {
  11. public static bool IsSubclassOfGeneric(Type type, Type genericBaseType)
  12. {
  13. while (type != null && type != typeof(object))
  14. {
  15. if (genericBaseType == (type.IsGenericType ? type.GetGenericTypeDefinition() : type))
  16. {
  17. return true;
  18. }
  19. if (type.BaseType == null)
  20. {
  21. return false;
  22. }
  23. type = type.BaseType;
  24. }
  25. return false;
  26. }
  27. public static AgentsMetadata GetAgentsMetadata(params Assembly[] assemblies)
  28. {
  29. var interfaceType = typeof(IMessage);
  30. var pairs = assemblies
  31. .SelectMany(assembly => assembly.GetTypes())
  32. .Where(type => interfaceType.IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
  33. .Select(t => (t, GetMessageDescriptor(t)));
  34. var descriptors = pairs.Select(t => t.Item2);
  35. var typeRegistry = TypeRegistry.FromMessages(descriptors);
  36. var types = pairs.ToDictionary(item => item.Item2?.FullName ?? "", item => item.t);
  37. var eventsMap = assemblies
  38. .SelectMany(assembly => assembly.GetTypes())
  39. .Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
  40. .Select(t => (t, t.GetInterfaces()
  41. .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>))
  42. .Select(i => GetMessageDescriptor(i.GetGenericArguments().First())?.FullName ?? "").ToHashSet()))
  43. .ToDictionary(item => item.t, item => item.Item2);
  44. var topicsMap = assemblies
  45. .SelectMany(assembly => assembly.GetTypes())
  46. .Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
  47. .Select(t => (t, t.GetCustomAttributes<TypeSubscriptionAttribute>().Select(a => a.Topic).ToHashSet()))
  48. .ToDictionary(item => item.t, item => item.Item2);
  49. var topicsPrefixMap = assemblies
  50. .SelectMany(assembly => assembly.GetTypes())
  51. .Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
  52. .Select(t => (t, t.GetCustomAttributes<TypePrefixSubscriptionAttribute>().Select(a => a.Topic).ToHashSet()))
  53. .ToDictionary(item => item.t, item => item.Item2);
  54. return new AgentsMetadata(typeRegistry, types, eventsMap, topicsMap, topicsPrefixMap);
  55. }
  56. /// <summary>
  57. /// Gets the message descriptor for the specified type.
  58. /// </summary>
  59. /// <param name="type">The type to get the message descriptor for.</param>
  60. /// <returns>The message descriptor if found; otherwise, <c>null</c>.</returns>
  61. public static MessageDescriptor? GetMessageDescriptor(Type type)
  62. {
  63. var property = type.GetProperty("Descriptor", BindingFlags.Static | BindingFlags.Public);
  64. return property?.GetValue(null) as MessageDescriptor;
  65. }
  66. }