C
C#17mo ago
berend

❔ getting all methods with an attribute in an optimized way

hey all, im trying to find a way to add all methods with an attribute to dictionary. i want to be able by entering a string in a console window for debugging purposes in unity. example of a methods im trying to find:
[Command]
public void MyCommandMethod()
{
// do something!
}
[Command]
public void MyCommandMethod()
{
// do something!
}
this is my current way of finding all methods with an attribute:
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
foreach (Type type in assembly.GetTypes())
{
foreach (MethodInfo method in type.GetMethods(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static))
{
CommandAttribute command = method.GetCustomAttribute<CommandAttribute>();
if (command != null)
{
string key = command.Name == string.Empty ? method.Name : command.Name;
if (!_availableCommands.ContainsKey(key))
{
_availableCommands.Add(key, method);
}
else
{
WriteLine($"command with name '{key}' has already been found!", Color.red);
}
}
}
}
}
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
foreach (Type type in assembly.GetTypes())
{
foreach (MethodInfo method in type.GetMethods(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static))
{
CommandAttribute command = method.GetCustomAttribute<CommandAttribute>();
if (command != null)
{
string key = command.Name == string.Empty ? method.Name : command.Name;
if (!_availableCommands.ContainsKey(key))
{
_availableCommands.Add(key, method);
}
else
{
WriteLine($"command with name '{key}' has already been found!", Color.red);
}
}
}
}
}
it works, but is obviously not very performant (takes multiple seconds to run this method). although i have seen other unity packages that dont seem to have any performance impact, so im sure its possible do it some other way. any help would be Ok
10 Replies
Sossenbinder
Sossenbinder17mo ago
Your current code would also examine assemblies of .Net itself I assume you can filter these out?
mtreit
mtreit17mo ago
If you're using reflection your perf is already going to be out the window
phaseshift
phaseshift17mo ago
Aside from filtering out assemblies starting with System etc, thats about the size of it
mtreit
mtreit17mo ago
Yeah, making sure you are only looking at relevant assemblies is probably going to make that much faster. Also, don't do this:
if (!_availableCommands.ContainsKey(key))
{
_availableCommands.Add(key, method);
}
if (!_availableCommands.ContainsKey(key))
{
_availableCommands.Add(key, method);
}
Use TryAdd instead
berend
berendOP17mo ago
yeah, but I dont really see any other way, but I may be missing something forgot about that one, thanks🙂
mtreit
mtreit17mo ago
Do you know how many assemblies you need to process? If you want to speed this up you can use a concurrent dictionary and process each assembly in parallel.
berend
berendOP17mo ago
I think so yes
mtreit
mtreit17mo ago
Just throw a Parallel.ForEach on there and use a ConcurrentDictionary, skip assemblies you know you don't need to process and you should be good. ez
berend
berendOP17mo ago
ah cool, didnt realize it would be that simple thanks!
Accord
Accord17mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server