diff --git a/src/Discord.Net.Core/Cache/ICached.cs b/src/Discord.Net.Core/Cache/ICached.cs index 19445598f..955b17017 100644 --- a/src/Discord.Net.Core/Cache/ICached.cs +++ b/src/Discord.Net.Core/Cache/ICached.cs @@ -11,8 +11,6 @@ namespace Discord void Update(TType model); TType ToModel(); - - TResult ToModel() where TResult : TType, new(); } public interface ICached diff --git a/src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs b/src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs index a6daa66d0..f13920c94 100644 --- a/src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs +++ b/src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs @@ -12,7 +12,7 @@ namespace Discord string Nickname { get; set; } string GuildAvatar { get; set; } ulong[] Roles { get; set; } - DateTimeOffset JoinedAt { get; set; } + DateTimeOffset? JoinedAt { get; set; } DateTimeOffset? PremiumSince { get; set; } bool IsDeaf { get; set; } bool IsMute { get; set; } diff --git a/src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs b/src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs index b8ad311fb..12a52f574 100644 --- a/src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs +++ b/src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs @@ -9,7 +9,6 @@ namespace Discord public interface IThreadMemberModel : IEntityModel { ulong? ThreadId { get; set; } - ulong? UserId { get; set; } DateTimeOffset JoinedAt { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/GuildMember.cs b/src/Discord.Net.Rest/API/Common/GuildMember.cs index 8a373fbab..e2321a3b1 100644 --- a/src/Discord.Net.Rest/API/Common/GuildMember.cs +++ b/src/Discord.Net.Rest/API/Common/GuildMember.cs @@ -39,8 +39,8 @@ namespace Discord.API get => Roles.GetValueOrDefault(Array.Empty()); set => throw new NotSupportedException(); } - DateTimeOffset IMemberModel.JoinedAt { - get => JoinedAt.GetValueOrDefault(); set => throw new NotSupportedException(); + DateTimeOffset? IMemberModel.JoinedAt { + get => JoinedAt.ToNullable(); set => throw new NotSupportedException(); } DateTimeOffset? IMemberModel.PremiumSince { diff --git a/src/Discord.Net.Rest/API/Common/ThreadMember.cs b/src/Discord.Net.Rest/API/Common/ThreadMember.cs index 11531c77f..10172cc70 100644 --- a/src/Discord.Net.Rest/API/Common/ThreadMember.cs +++ b/src/Discord.Net.Rest/API/Common/ThreadMember.cs @@ -15,7 +15,6 @@ namespace Discord.API public DateTimeOffset JoinTimestamp { get; set; } ulong? IThreadMemberModel.ThreadId { get => ThreadId.ToNullable(); set => throw new NotSupportedException(); } - ulong? IThreadMemberModel.UserId { get => UserId.ToNullable(); set => throw new NotSupportedException(); } DateTimeOffset IThreadMemberModel.JoinedAt { get => JoinTimestamp; set => throw new NotSupportedException(); } ulong IEntityModel.Id { get => UserId.GetValueOrDefault(0); set => throw new NotSupportedException(); } } diff --git a/src/Discord.Net.WebSocket/Cache/CacheRunMode.cs b/src/Discord.Net.WebSocket/Cache/CacheRunMode.cs deleted file mode 100644 index f53719e06..000000000 --- a/src/Discord.Net.WebSocket/Cache/CacheRunMode.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord.WebSocket -{ - public enum CacheRunMode - { - /// - /// The cache should preform a synchronous cache lookup. - /// - Sync, - - /// - /// The cache should preform either a or asynchronous cache lookup. - /// - Async - } -} diff --git a/src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs b/src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs index 136d88a75..7a146677b 100644 --- a/src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs +++ b/src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs @@ -12,6 +12,16 @@ namespace Discord.WebSocket private readonly ConcurrentDictionary _storeCache = new(); private readonly ConcurrentDictionary _subStoreCache = new(); + private readonly Dictionary _models = new() + { + { typeof(IUserModel), typeof(API.User) }, + { typeof(ICurrentUserModel), typeof(API.CurrentUser) }, + { typeof(IMemberModel), typeof(API.GuildMember) }, + { typeof(IThreadMemberModel), typeof(API.ThreadMember)}, + { typeof(IPresenceModel), typeof(API.Presence)}, + { typeof(IActivityModel), typeof(API.Game)} + }; + private class DefaultEntityStore : IEntityStore where TModel : IEntityModel where TId : IEquatable @@ -23,44 +33,72 @@ namespace Discord.WebSocket _cache = cache; } - public ValueTask AddOrUpdateAsync(TModel model, CacheRunMode runmode) + public TModel Get(TId id) { - _cache.AddOrUpdate(model.Id, model, (_, __) => model); + if (_cache.TryGetValue(id, out var model)) + return model; return default; } - - public ValueTask AddOrUpdateBatchAsync(IEnumerable models, CacheRunMode runmode) + public IEnumerable GetAll() + { + return _cache.Select(x => x.Value); + } + public void AddOrUpdate(TModel model) + { + _cache.AddOrUpdate(model.Id, model, (_, __) => model); + } + public void AddOrUpdateBatch(IEnumerable models) { foreach (var model in models) _cache.AddOrUpdate(model.Id, model, (_, __) => model); - return default; + } + public void Remove(TId id) + { + _cache.TryRemove(id, out _); + } + public void PurgeAll() + { + _cache.Clear(); } - public IAsyncEnumerable GetAllAsync(CacheRunMode runmode) + ValueTask IEntityStore.GetAsync(TId id) => new ValueTask(Get(id)); + IAsyncEnumerable IEntityStore.GetAllAsync() { - var coll = _cache.Select(x => x.Value).GetEnumerator(); - return AsyncEnumerable.Create((_) => AsyncEnumerator.Create( - () => new ValueTask(coll.MoveNext()), - () => coll.Current, - () => new ValueTask())); + var enumerator = GetAll().GetEnumerator(); + return AsyncEnumerable.Create((cancellationToken) + => AsyncEnumerator.Create( + () => new ValueTask(enumerator.MoveNext()), + () => enumerator.Current, + () => new ValueTask()) + ); } - public ValueTask GetAsync(TId id, CacheRunMode runmode) + ValueTask IEntityStore.AddOrUpdateAsync(TModel model) { - if (_cache.TryGetValue(id, out var model)) - return new ValueTask(model); + AddOrUpdate(model); return default; } - public ValueTask RemoveAsync(TId id, CacheRunMode runmode) + ValueTask IEntityStore.AddOrUpdateBatchAsync(IEnumerable models) { - _cache.TryRemove(id, out _); + AddOrUpdateBatch(models); return default; } - - public ValueTask PurgeAllAsync(CacheRunMode runmode) + ValueTask IEntityStore.RemoveAsync(TId id) { - _cache.Clear(); + Remove(id); return default; } + ValueTask IEntityStore.PurgeAllAsync() + { + PurgeAll(); + return default; + } + } + + public Type GetModel() + { + if (_models.TryGetValue(typeof(TInterface), out var t)) + return t; + return null; } public virtual ValueTask> GetStoreAsync() diff --git a/src/Discord.Net.WebSocket/Cache/ICacheProvider.cs b/src/Discord.Net.WebSocket/Cache/ICacheProvider.cs index f4ae3b994..42238a16e 100644 --- a/src/Discord.Net.WebSocket/Cache/ICacheProvider.cs +++ b/src/Discord.Net.WebSocket/Cache/ICacheProvider.cs @@ -8,6 +8,8 @@ namespace Discord.WebSocket { public interface ICacheProvider { + Type GetModel(); + ValueTask> GetStoreAsync() where TModel : IEntityModel where TId : IEquatable; @@ -21,11 +23,17 @@ namespace Discord.WebSocket where TModel : IEntityModel where TId : IEquatable { - ValueTask GetAsync(TId id, CacheRunMode runmode); - IAsyncEnumerable GetAllAsync(CacheRunMode runmode); - ValueTask AddOrUpdateAsync(TModel model, CacheRunMode runmode); - ValueTask AddOrUpdateBatchAsync(IEnumerable models, CacheRunMode runmode); - ValueTask RemoveAsync(TId id, CacheRunMode runmode); - ValueTask PurgeAllAsync(CacheRunMode runmode); + ValueTask GetAsync(TId id); + TModel Get(TId id); + IAsyncEnumerable GetAllAsync(); + IEnumerable GetAll(); + ValueTask AddOrUpdateAsync(TModel model); + void AddOrUpdate(TModel model); + ValueTask AddOrUpdateBatchAsync(IEnumerable models); + void AddOrUpdateBatch(IEnumerable models); + ValueTask RemoveAsync(TId id); + void Remove(TId id); + ValueTask PurgeAllAsync(); + void PurgeAll(); } } diff --git a/src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs b/src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs index ccbcc2f77..86c59d0bc 100644 --- a/src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs +++ b/src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs @@ -92,28 +92,6 @@ namespace Discord.WebSocket } } - private TResult RunOrThrowValueTask(ValueTask t) - { - if (_allowSyncWaits) - { - return t.GetAwaiter().GetResult(); - } - else if (t.IsCompleted) - return t.Result; - else - throw new InvalidOperationException("Cannot run asynchronous value task in synchronous context"); - } - - private void RunOrThrowValueTask(ValueTask t) - { - if (_allowSyncWaits) - { - t.GetAwaiter().GetResult(); - } - else if (!t.IsCompleted) - throw new InvalidOperationException("Cannot run asynchronous value task in synchronous context"); - } - public async ValueTask InitializeAsync() { _store ??= await _cacheProvider.GetStoreAsync().ConfigureAwait(false); @@ -137,7 +115,7 @@ namespace Discord.WebSocket return entity; } - var model = RunOrThrowValueTask(_store.GetAsync(id, CacheRunMode.Sync)); + var model = _store.Get(id); if (model != null) { @@ -156,7 +134,7 @@ namespace Discord.WebSocket return entity; } - var model = await _store.GetAsync(id, CacheRunMode.Async).ConfigureAwait(false); + var model = await _store.GetAsync(id).ConfigureAwait(false); if (model != null) { @@ -175,7 +153,7 @@ namespace Discord.WebSocket public IEnumerable GetAll() { - var models = RunOrThrowValueTask(_store.GetAllAsync(CacheRunMode.Sync).ToArrayAsync()); + var models = _store.GetAll(); return models.Select(x => { var entity = _entityBuilder(x); @@ -186,7 +164,7 @@ namespace Discord.WebSocket public async IAsyncEnumerable GetAllAsync() { - await foreach(var model in _store.GetAllAsync(CacheRunMode.Async)) + await foreach(var model in _store.GetAllAsync()) { var entity = _entityBuilder(model); _references.TryAdd(model.Id, new CacheReference(entity)); @@ -212,13 +190,13 @@ namespace Discord.WebSocket return (TEntity)entity; var model = valueFactory(id); - await AddOrUpdateAsync(model); + await AddOrUpdateAsync(model).ConfigureAwait(false); return _entityBuilder(model); } public void AddOrUpdate(TModel model) { - RunOrThrowValueTask(_store.AddOrUpdateAsync(model, CacheRunMode.Sync)); + _store.AddOrUpdate(model); if (TryGetReference(model.Id, out var reference)) reference.Update(model); } @@ -227,14 +205,13 @@ namespace Discord.WebSocket { if (TryGetReference(model.Id, out var reference)) reference.Update(model); - return _store.AddOrUpdateAsync(model, CacheRunMode.Async); + return _store.AddOrUpdateAsync(model); } public void BulkAddOrUpdate(IEnumerable models) { - RunOrThrowValueTask(_store.AddOrUpdateBatchAsync(models, CacheRunMode.Sync)); - - foreach(var model in models) + _store.AddOrUpdateBatch(models); + foreach (var model in models) { if (_references.TryGetValue(model.Id, out var rf) && rf.Reference.TryGetTarget(out var entity)) entity.Update(model); @@ -243,7 +220,7 @@ namespace Discord.WebSocket public async ValueTask BulkAddOrUpdateAsync(IEnumerable models) { - await _store.AddOrUpdateBatchAsync(models, CacheRunMode.Async).ConfigureAwait(false); + await _store.AddOrUpdateBatchAsync(models).ConfigureAwait(false); foreach (var model in models) { @@ -254,26 +231,26 @@ namespace Discord.WebSocket public void Remove(TId id) { - RunOrThrowValueTask(_store.RemoveAsync(id, CacheRunMode.Sync)); + _store.Remove(id); _references.TryRemove(id, out _); } public ValueTask RemoveAsync(TId id) { _references.TryRemove(id, out _); - return _store.RemoveAsync(id, CacheRunMode.Async); + return _store.RemoveAsync(id); } public void Purge() { - RunOrThrowValueTask(_store.PurgeAllAsync(CacheRunMode.Sync)); + _store.PurgeAll(); _references.Clear(); } public ValueTask PurgeAsync() { _references.Clear(); - return _store.PurgeAllAsync(CacheRunMode.Async); + return _store.PurgeAllAsync(); } TEntity ILookupReferenceStore.Get(TId id) => Get(id); @@ -380,5 +357,24 @@ namespace Discord.WebSocket _threadMemberLock.Release(); } } + + public ReferenceStore GetThreadMemberStore(ulong threadId) + => _threadMemberStores.TryGetValue(threadId, out var store) ? store : null; + + public TModel GetModel() + where TFallback : class, TModel, new() + { + var type = _cacheProvider.GetModel(); + + if (type != null) + { + if (!type.GetInterfaces().Contains(typeof(TModel))) + throw new InvalidOperationException($"Cannot use {type.Name} as a model for {typeof(TModel).Name}"); + + return (TModel)Activator.CreateInstance(type); + } + else + return new TFallback(); + } } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 9b25eb741..f876283a4 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -74,7 +74,6 @@ namespace Discord.WebSocket /// public bool? IsPending { get; private set; } - /// public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); /// @@ -159,7 +158,7 @@ namespace Discord.WebSocket } internal void Update(MemberModel model) { - _joinedAtTicks = model.JoinedAt.UtcTicks; + _joinedAtTicks = model.JoinedAt.HasValue ? model.JoinedAt.Value.UtcTicks : null; Nickname = model.Nickname; GuildAvatarId = model.GuildAvatar; UpdateRoles(model.Roles); @@ -232,6 +231,17 @@ namespace Discord.WebSocket internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; + public override void Dispose() + { + if (IsFreed) + return; + + GC.SuppressFinalize(this); + Discord.StateManager.GetMemberStore(_guildId)?.RemoveReference(Id); + IsFreed = true; + } + ~SocketGuildUser() => Dispose(); + #endregion #region IGuildUser @@ -249,7 +259,7 @@ namespace Discord.WebSocket #region Cache - private struct CacheModel : MemberModel + private class CacheModel : MemberModel { public ulong Id { get; set; } public string Nickname { get; set; } @@ -258,7 +268,7 @@ namespace Discord.WebSocket public ulong[] Roles { get; set; } - public DateTimeOffset JoinedAt { get; set; } + public DateTimeOffset? JoinedAt { get; set; } public DateTimeOffset? PremiumSince { get; set; } @@ -271,40 +281,25 @@ namespace Discord.WebSocket public DateTimeOffset? CommunicationsDisabledUntil { get; set; } } internal new MemberModel ToModel() - => ToModel(); - - internal new TModel ToModel() where TModel : MemberModel, new() { - return new TModel - { - Id = Id, - CommunicationsDisabledUntil = TimedOutUntil, - GuildAvatar = GuildAvatarId, - IsDeaf = IsDeafened, - IsMute = IsMuted, - IsPending = IsPending, - JoinedAt = JoinedAt ?? DateTimeOffset.UtcNow, // review: nullable joined at here? should our model reflect this? - Nickname = Nickname, - PremiumSince = PremiumSince, - Roles = _roleIds.ToArray() - }; + var model = Discord.StateManager.GetModel(); + model.Id = Id; + model.Nickname = Nickname; + model.GuildAvatar = GuildAvatarId; + model.Roles = _roleIds.ToArray(); + model.JoinedAt = JoinedAt; + model.PremiumSince = PremiumSince; + model.IsDeaf = IsDeafened; + model.IsMute = IsMuted; + model.IsPending = IsPending; + model.CommunicationsDisabledUntil = TimedOutUntil; + return model; } MemberModel ICached.ToModel() => ToModel(); - TResult ICached.ToModel() - => ToModel(); - void ICached.Update(MemberModel model) => Update(model); - - public override void Dispose() - { - GC.SuppressFinalize(this); - Discord.StateManager.GetMemberStore(_guildId)?.RemoveReference(Id); - } - ~SocketGuildUser() => Dispose(); - #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs index aa0220453..b1a4629ad 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs @@ -112,7 +112,6 @@ namespace Discord.WebSocket internal SocketPresence Clone() => MemberwiseClone() as SocketPresence; ~SocketPresence() => Dispose(); - public void Dispose() { if (IsFreed) @@ -128,7 +127,7 @@ namespace Discord.WebSocket } #region Cache - private struct CacheModel : Model + private class CacheModel : Model { public UserStatus Status { get; set; } @@ -187,48 +186,43 @@ namespace Discord.WebSocket } internal Model ToModel() - => ToModel(); - - internal TModel ToModel() where TModel : Model, new() { - return new TModel + var model = Discord.StateManager.GetModel(); + model.Status = Status; + model.ActiveClients = ActiveClients.ToArray(); + model.UserId = UserId; + model.GuildId = GuildId; + model.Activities = Activities.Select(x => { - Status = Status, - ActiveClients = ActiveClients.ToArray(), - UserId = UserId, - GuildId = GuildId, - Activities = Activities.Select(x => + switch (x) + { + case Game game: + switch (game) + { + case RichGame richGame: + return richGame.ToModel(); + case SpotifyGame spotify: + return spotify.ToModel(); + case CustomStatusGame custom: + return custom.ToModel(); + case StreamingGame stream: + return stream.ToModel(); + } + break; + } + + return new ActivityCacheModel { - switch (x) - { - case Game game: - switch (game) - { - case RichGame richGame: - return richGame.ToModel(); - case SpotifyGame spotify: - return spotify.ToModel(); - case CustomStatusGame custom: - return custom.ToModel(); - case StreamingGame stream: - return stream.ToModel(); - } - break; - } - - return new ActivityCacheModel - { - Name = x.Name, - Details = x.Details, - Flags = x.Flags, - Type = x.Type - }; - }).ToArray(), - }; + Name = x.Name, + Details = x.Details, + Flags = x.Flags, + Type = x.Type + }; + }).ToArray(); + return model; } Model ICached.ToModel() => ToModel(); - TResult ICached.ToModel() => ToModel(); void ICached.Update(Model model) => Update(model); bool ICached.IsFreed => IsFreed; diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index 1d1c3bb6c..6047c34f1 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -97,7 +97,7 @@ namespace Discord.WebSocket } #region Cache - private struct CacheModel : Model + private class CacheModel : Model { public bool? IsVerified { get; set; } @@ -125,29 +125,23 @@ namespace Discord.WebSocket } internal new Model ToModel() - => ToModel(); - - internal new TModel ToModel() where TModel : Model, new() { - return new TModel - { - Avatar = AvatarId, - Discriminator = Discriminator, - Email = Email, - Flags = Flags, - Id = Id, - IsBot = IsBot, - IsMfaEnabled = IsMfaEnabled, - IsVerified = IsVerified, - Locale = Locale, - PremiumType = this.PremiumType, - PublicFlags = PublicFlags ?? UserProperties.None, - Username = Username - }; + var model = Discord.StateManager.GetModel(); + model.Avatar = AvatarId; + model.Discriminator = Discriminator; + model.Email = Email; + model.Flags = Flags; + model.IsBot = IsBot; + model.IsMfaEnabled = IsMfaEnabled; + model.Locale = Locale; + model.PremiumType = PremiumType; + model.PublicFlags = PublicFlags ?? UserProperties.None; + model.Username = Username; + model.Id = Id; + return model; } Model ICached.ToModel() => ToModel(); - TResult ICached.ToModel() => ToModel(); void ICached.Update(Model model) => Update(model); #endregion } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs index 48aebc92e..fc67a1e1b 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs @@ -151,14 +151,14 @@ namespace Discord.WebSocket internal static SocketThreadUser Create(SocketGuild guild, SocketThreadChannel thread, Model model, SocketGuildUser member) { - var entity = new SocketThreadUser(guild.Discord, guild.Id, thread.Id, model.UserId.Value); + var entity = new SocketThreadUser(guild.Discord, guild.Id, thread.Id, model.Id); entity.Update(model); return entity; } internal static SocketThreadUser Create(DiscordSocketClient client, ulong guildId, ulong threadId, Model model) { - var entity = new SocketThreadUser(client, guildId, threadId, model.UserId.Value); + var entity = new SocketThreadUser(client, guildId, threadId, model.Id); entity.Update(model); return entity; } @@ -242,7 +242,12 @@ namespace Discord.WebSocket public override void Dispose() { + if (IsFreed) + return; + GC.SuppressFinalize(this); + Discord.StateManager.GetThreadMemberStore(_threadId)?.RemoveReference(Id); + IsFreed = true; } @@ -255,27 +260,21 @@ namespace Discord.WebSocket #region Cache private class CacheModel : Model { + public ulong Id { get; set; } public ulong? ThreadId { get; set; } - public ulong? UserId { get; set; } public DateTimeOffset JoinedAt { get; set; } - - ulong IEntityModel.Id { get => UserId.GetValueOrDefault(); set => throw new NotSupportedException(); } } - internal new Model ToModel() => ToModel(); - - internal new TModel ToModel() where TModel : Model, new() + internal new Model ToModel() { - return new TModel - { - JoinedAt = ThreadJoinedAt, - ThreadId = _threadId, - UserId = Id - }; + var model = Discord.StateManager.GetModel(); + model.Id = Id; + model.ThreadId = _threadId; + model.JoinedAt = ThreadJoinedAt; + return model; } Model ICached.ToModel() => ToModel(); - TResult ICached.ToModel() => ToModel(); void ICached.Update(Model model) => Update(model); #endregion } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 43b3b0e54..3821fac50 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -137,29 +137,20 @@ namespace Discord.WebSocket public ulong Id { get; set; } } - internal TModel ToModel() where TModel : Model, new() + internal Model ToModel() { - return new TModel - { - Avatar = AvatarId, - Discriminator = Discriminator, - Id = Id, - IsBot = IsBot, - Username = Username - }; + var model = Discord.StateManager.GetModel(); + model.Avatar = AvatarId; + model.Discriminator = Discriminator; + model.Id = Id; + model.IsBot = IsBot; + model.Username = Username; + return model; } - internal Model ToModel() - => ToModel(); - Model ICached.ToModel() => ToModel(); - - TResult ICached.ToModel() - => ToModel(); - void ICached.Update(Model model) => Update(model); - bool ICached.IsFreed => IsFreed; #endregion