diff --git a/X10D.DSharpPlus/src/DiscordGuildExtensions.cs b/X10D.DSharpPlus/src/DiscordGuildExtensions.cs
index 7519bfa..c03016b 100644
--- a/X10D.DSharpPlus/src/DiscordGuildExtensions.cs
+++ b/X10D.DSharpPlus/src/DiscordGuildExtensions.cs
@@ -1,5 +1,6 @@
using DSharpPlus;
using DSharpPlus.Entities;
+using DSharpPlus.Exceptions;
namespace X10D.DSharpPlus;
@@ -27,6 +28,39 @@ public static class DiscordGuildExtensions
await Task.WhenAll(guild.Threads.Values.Select(t => t.JoinThreadAsync())).ConfigureAwait(false);
}
+ ///
+ /// Gets a guild member by their ID. If the member is not found, is returned instead of
+ /// being thrown.
+ ///
+ /// The guild whose member list to search.
+ /// The ID of the member to retrieve.
+ /// is .
+ public static async Task GetMemberOrNullAsync(this DiscordGuild guild, ulong userId)
+ {
+#if NET6_0_OR_GREATER
+ ArgumentNullException.ThrowIfNull(guild);
+#else
+ if (guild is null)
+ {
+ throw new ArgumentNullException(nameof(guild));
+ }
+#endif
+
+ try
+ {
+ // we should never use exceptions for flow control but this is D#+ we're talking about.
+ // NotFoundException isn't even documented, and yet it gets thrown when a member doesn't exist.
+ // so this method should hopefully clearly express that - and at least using exceptions for flow control *here*,
+ // removes the need to do the same in consumer code.
+ // god I hate this.
+ return await guild.GetMemberAsync(userId).ConfigureAwait(false);
+ }
+ catch (NotFoundException)
+ {
+ return null;
+ }
+ }
+
///
/// Normalizes a so that the internal client is assured to be a specified value.
///