Skip to content

Commit fb41e3a

Browse files
committed
feat!: replace union accessors with generic Is, As and TryGet and implicit conversions
1 parent 2712172 commit fb41e3a

6 files changed

Lines changed: 49 additions & 23 deletions

File tree

‎README.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ IVRChat vrchat = new VRChatClientBuilder() // More options available
6262
var currentUser = await vrchat.LoginAsync();
6363
Console.WriteLine($"Logged in as {currentUser.DisplayName}!");
6464

65-
var user = (await vrchat.Users.GetUserAsync("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e")).GetUser();
65+
User user = await vrchat.Users.GetUserAsync("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e");
6666
Console.WriteLine($"Found user {user.DisplayName}, joined at {user.DateJoined}");
6767

6868
var world = await vrchat.Worlds.GetWorldAsync("wrld_ba913a96-fac4-4048-a062-9aa5db092812");
@@ -162,7 +162,7 @@ IVRChat vrchat = new VRChatClientBuilder() // More options available
162162
.Build();
163163

164164
var response = await vrchat.Authentication.GetCurrentUserAsync();
165-
var methods = (response.ActualInstance as RequiresTwoFactorAuth)?.VarRequiresTwoFactorAuth ?? new List<TwoFactorAuthType>();
165+
var methods = response.TryGet<RequiresTwoFactorAuth>(out var pending) ? pending.VarRequiresTwoFactorAuth : new List<TwoFactorAuthType>();
166166

167167
if(methods.Contains(TwoFactorAuthType.EmailOtp))
168168
{
@@ -179,7 +179,7 @@ else if(methods.Contains(TwoFactorAuthType.Totp))
179179
var otpResponse = await vrchat.Authentication.Verify2FAAsync(new TwoFactorAuthCode(code));
180180
}
181181

182-
var user = (await vrchat.Authentication.GetCurrentUserAsync()).GetCurrentUser();
182+
CurrentUser user = await vrchat.Authentication.GetCurrentUserAsync();
183183

184184
Console.WriteLine($"Logged in as {user.DisplayName}!");
185185
```
@@ -221,7 +221,7 @@ try
221221
// so we can see what the API expects from us
222222
ApiResponse<CurrentUserLoginResponse> currentUserResp = authApi.GetCurrentUserWithHttpInfo();
223223

224-
if(currentUserResp.Data.ActualInstance is RequiresTwoFactorAuth pending)
224+
if(currentUserResp.Data.TryGet<RequiresTwoFactorAuth>(out var pending))
225225
{
226226
if (pending.VarRequiresTwoFactorAuth.Contains(TwoFactorAuthType.EmailOtp)) // If the API wants us to send an Email OTP code
227227
{
@@ -235,10 +235,10 @@ try
235235
}
236236

237237
// We can now get our CurrentUser :D
238-
CurrentUser currentUser = authApi.GetCurrentUser().GetCurrentUser();
238+
CurrentUser currentUser = authApi.GetCurrentUser();
239239
Console.WriteLine("Logged in as {0}", currentUser.DisplayName);
240240

241-
User user = userApi.GetUser("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e").GetUser();
241+
User user = userApi.GetUser("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e");
242242
Console.WriteLine("Found user {0}, joined {1}", user.DisplayName, user.DateJoined);
243243

244244
World world = worldApi.GetWorld("wrld_ba913a96-fac4-4048-a062-9aa5db092812");

‎examples/VRChat.API.Examples.AspNetCore/Controllers/HomeController.cs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Mvc;
22
using VRChat.API.Client;
3+
using VRChat.API.Model;
34

45
namespace VRChat.API.Examples.AspNetCore.Controllers;
56

@@ -23,7 +24,7 @@ public IActionResult Index()
2324
[Route("/api/users/current")]
2425
public async Task<IActionResult> GetCurrentUserAsync()
2526
{
26-
var user = (await _vrchat.Authentication.GetCurrentUserAsync()).GetCurrentUser();
27+
CurrentUser user = await _vrchat.Authentication.GetCurrentUserAsync();
2728

2829
// Profile fields (bio, bio links, badges, ...) are no longer part of CurrentUser.
2930
// They live behind getPublicProfile; asSelf includes the owner-only view.
@@ -45,7 +46,7 @@ public async Task<IActionResult> GetCurrentUserAsync()
4546
[Route("/api/users/{id}")]
4647
public async Task<IActionResult> GetUserByIdAsync(string id)
4748
{
48-
var user = (await _vrchat.Users.GetUserAsync(id)).GetUser();
49+
User user = await _vrchat.Users.GetUserAsync(id);
4950

5051
// User no longer carries the profile or current-avatar fields; fetch them from the
5152
// public profile instead.

‎examples/VRChat.API.Examples.Console/Program.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static async Task Main(string[] args)
2121
var currentUser = await vrchat.LoginAsync();
2222
System.Console.WriteLine($"Logged in as {currentUser.DisplayName}!");
2323

24-
var user = (await vrchat.Users.GetUserAsync("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e")).GetUser();
24+
User user = await vrchat.Users.GetUserAsync("usr_f2049d71-e76b-42d2-a8bd-43deec9c004e");
2525
System.Console.WriteLine($"Found user {user.DisplayName}, joined at {user.DateJoined}");
2626

2727
var world = await vrchat.Worlds.GetWorldAsync("wrld_ba913a96-fac4-4048-a062-9aa5db092812");

‎templates/modelAnyOf.mustache‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,12 @@
7373
{{^vendorExtensions.x-duplicated-data-type}}
7474
{{^isNull}}
7575

76+
{{^isAnyType}}{{^isFreeFormObject}}
7677
/// <summary>
77-
/// Get the actual instance of `{{dataType}}`. If the actual instance is not `{{dataType}}`,
78-
/// the InvalidClassException will be thrown
78+
/// Converts to the <c>{{dataType}}</c> this instance holds, throwing <see cref="InvalidCastException"/> when it holds another type.
7979
/// </summary>
80-
/// <returns>An instance of {{dataType}}</returns>
81-
public {{{dataType}}} Get{{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}}{{#isArray}}{{#lambda.titlecase}}{{{dataFormat}}}{{/lambda.titlecase}}{{/isArray}}()
82-
{
83-
return ({{{dataType}}})ActualInstance;
84-
}
80+
public static implicit operator {{{dataType}}}({{classname}} value) => ({{{dataType}}})value?.ActualInstance;
81+
{{/isFreeFormObject}}{{/isAnyType}}
8582
{{/isNull}}
8683
{{/vendorExtensions.x-duplicated-data-type}}
8784
{{/composedSchemas.anyOf}}

‎templates/modelOneOf.mustache‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,12 @@
7373
{{^vendorExtensions.x-duplicated-data-type}}
7474
{{^isNull}}
7575

76+
{{^isAnyType}}{{^isFreeFormObject}}
7677
/// <summary>
77-
/// Get the actual instance of `{{dataType}}`. If the actual instance is not `{{dataType}}`,
78-
/// the InvalidClassException will be thrown
78+
/// Converts to the <c>{{dataType}}</c> this instance holds, throwing <see cref="InvalidCastException"/> when it holds another type.
7979
/// </summary>
80-
/// <returns>An instance of {{dataType}}</returns>
81-
public {{{dataType}}} Get{{#lambda.titlecase}}{{baseType}}{{/lambda.titlecase}}{{#isArray}}{{#lambda.titlecase}}{{{dataFormat}}}{{/lambda.titlecase}}{{/isArray}}()
82-
{
83-
return ({{{dataType}}})this.ActualInstance;
84-
}
80+
public static implicit operator {{{dataType}}}({{classname}} value) => ({{{dataType}}})value?.ActualInstance;
81+
{{/isFreeFormObject}}{{/isAnyType}}
8582
{{/isNull}}
8683
{{/vendorExtensions.x-duplicated-data-type}}
8784
{{/composedSchemas.oneOf}}

‎wrapper/VRChat.API/Model/GeneratedModelExtensions.cs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,35 @@ public partial class TwoFactorAuthCode : ITwoFactorCode { }
1111
/// two-factor code is accepted.
1212
/// </summary>
1313
public partial class TwoFactorEmailCode : ITwoFactorCode { }
14+
15+
/// <summary>
16+
/// Additions to the generated <see cref="AbstractOpenAPISchema"/>, which every union type extends.
17+
/// </summary>
18+
public abstract partial class AbstractOpenAPISchema
19+
{
20+
/// <summary>
21+
/// Whether this instance holds a <typeparamref name="T"/>.
22+
/// </summary>
23+
public bool Is<T>() => ActualInstance is T;
24+
25+
/// <summary>
26+
/// The <typeparamref name="T"/> this instance holds, throwing <see cref="System.InvalidCastException"/> when it holds another type.
27+
/// </summary>
28+
public T As<T>() => (T)ActualInstance;
29+
30+
/// <summary>
31+
/// Gets the <typeparamref name="T"/> this instance holds, if it holds one.
32+
/// </summary>
33+
public bool TryGet<T>(out T value)
34+
{
35+
if (ActualInstance is T instance)
36+
{
37+
value = instance;
38+
return true;
39+
}
40+
41+
value = default;
42+
return false;
43+
}
44+
}
1445
}

0 commit comments

Comments
 (0)