use specified nullability in reflection API (#837)

This commit is contained in:
Jesse Plamondon-Willard 2022-04-16 11:10:13 -04:00
parent c0d0ad0282
commit 2dc20be5f7
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
11 changed files with 35 additions and 31 deletions

View File

@ -98,7 +98,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
this.AggressiveMemoryOptimizations = aggressiveMemoryOptimizations;
// get asset data
this.BaseDisposableReferences = reflection.GetField<List<IDisposable>>(this, "disposableAssets").GetValue()
this.BaseDisposableReferences = reflection.GetField<List<IDisposable>?>(this, "disposableAssets").GetValue()
?? throw new InvalidOperationException("Can't initialize content manager: the required 'disposableAssets' field wasn't found.");
}

View File

@ -160,7 +160,7 @@ namespace StardewModdingAPI.Framework
/// <param name="reflection">The reflection helper with which to access private fields.</param>
public static bool IsOpen(this SpriteBatch spriteBatch, Reflector reflection)
{
return reflection.GetField<bool>(spriteBatch, "_beginCalled")!.GetValue();
return reflection.GetField<bool>(spriteBatch, "_beginCalled").GetValue();
}
}
}

View File

@ -35,7 +35,7 @@ namespace StardewModdingAPI.Framework
this.Mods.Add(metadata);
}
/// <summary>Track a mod's assembly for use via <see cref="GetFrom"/>.</summary>
/// <summary>Track a mod's assembly for use via <see cref="GetFrom(Type?)"/>.</summary>
/// <param name="metadata">The mod metadata.</param>
/// <param name="modAssembly">The mod assembly.</param>
public void TrackAssemblies(IModMetadata metadata, Assembly modAssembly)

View File

@ -56,11 +56,11 @@ namespace StardewModdingAPI.Framework.Reflection
}
/// <inheritdoc />
public TValue? GetValue()
public TValue GetValue()
{
try
{
return (TValue?)this.FieldInfo.GetValue(this.Parent);
return (TValue)this.FieldInfo.GetValue(this.Parent)!;
}
catch (InvalidCastException)
{
@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.Reflection
}
/// <inheritdoc />
public void SetValue(TValue? value)
public void SetValue(TValue value)
{
try
{

View File

@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework.Reflection
}
/// <inheritdoc />
public TValue? Invoke<TValue>(params object?[] arguments)
public TValue Invoke<TValue>(params object?[] arguments)
{
// invoke method
object? result;
@ -75,7 +75,7 @@ namespace StardewModdingAPI.Framework.Reflection
// cast return value
try
{
return (TValue?)result;
return (TValue)result!;
}
catch (InvalidCastException)
{

View File

@ -14,10 +14,10 @@ namespace StardewModdingAPI.Framework.Reflection
private readonly string DisplayName;
/// <summary>The underlying property getter.</summary>
private readonly Func<TValue?>? GetMethod;
private readonly Func<TValue>? GetMethod;
/// <summary>The underlying property setter.</summary>
private readonly Action<TValue?>? SetMethod;
private readonly Action<TValue>? SetMethod;
/*********
@ -56,13 +56,13 @@ namespace StardewModdingAPI.Framework.Reflection
this.PropertyInfo = property;
if (this.PropertyInfo.GetMethod != null)
this.GetMethod = (Func<TValue?>)Delegate.CreateDelegate(typeof(Func<TValue?>), obj, this.PropertyInfo.GetMethod);
this.GetMethod = (Func<TValue>)Delegate.CreateDelegate(typeof(Func<TValue>), obj, this.PropertyInfo.GetMethod);
if (this.PropertyInfo.SetMethod != null)
this.SetMethod = (Action<TValue?>)Delegate.CreateDelegate(typeof(Action<TValue?>), obj, this.PropertyInfo.SetMethod);
this.SetMethod = (Action<TValue>)Delegate.CreateDelegate(typeof(Action<TValue>), obj, this.PropertyInfo.SetMethod);
}
/// <inheritdoc />
public TValue? GetValue()
public TValue GetValue()
{
if (this.GetMethod == null)
throw new InvalidOperationException($"The {this.DisplayName} property has no get method.");
@ -82,7 +82,7 @@ namespace StardewModdingAPI.Framework.Reflection
}
/// <inheritdoc />
public void SetValue(TValue? value)
public void SetValue(TValue value)
{
if (this.SetMethod == null)
throw new InvalidOperationException($"The {this.DisplayName} property has no set method.");

View File

@ -113,13 +113,13 @@ namespace StardewModdingAPI.Framework
{
case LidgrenClient:
{
string address = this.Reflection.GetField<string>(client, "address").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: no valid address found.");
string address = this.Reflection.GetField<string?>(client, "address").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: no valid address found.");
return new SLidgrenClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage);
}
case GalaxyNetClient:
{
GalaxyID address = this.Reflection.GetField<GalaxyID>(client, "lobbyId").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: no valid address found.");
GalaxyID address = this.Reflection.GetField<GalaxyID?>(client, "lobbyId").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: no valid address found.");
return new SGalaxyNetClient(address, this.OnClientProcessingMessage, this.OnClientSendingMessage);
}
@ -137,13 +137,13 @@ namespace StardewModdingAPI.Framework
{
case LidgrenServer:
{
IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: the required 'gameServer' field wasn't found.");
IGameServer gameServer = this.Reflection.GetField<IGameServer?>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize base networking client: the required 'gameServer' field wasn't found.");
return new SLidgrenServer(gameServer, this, this.OnServerProcessingMessage);
}
case GalaxyNetServer:
{
IGameServer gameServer = this.Reflection.GetField<IGameServer>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: the required 'gameServer' field wasn't found.");
IGameServer gameServer = this.Reflection.GetField<IGameServer?>(server, "gameServer").GetValue() ?? throw new InvalidOperationException("Can't initialize GOG networking client: the required 'gameServer' field wasn't found.");
return new SGalaxyNetServer(gameServer, this, this.OnServerProcessingMessage);
}

View File

@ -17,10 +17,10 @@ namespace StardewModdingAPI
** Public methods
*********/
/// <summary>Get the field value.</summary>
TValue? GetValue();
TValue GetValue();
/// <summary>Set the field value.</summary>
//// <param name="value">The value to set.</param>
void SetValue(TValue? value);
void SetValue(TValue value);
}
}

View File

@ -18,7 +18,7 @@ namespace StardewModdingAPI
/// <summary>Invoke the method.</summary>
/// <typeparam name="TValue">The return type.</typeparam>
/// <param name="arguments">The method arguments to pass in.</param>
TValue? Invoke<TValue>(params object?[] arguments);
TValue Invoke<TValue>(params object?[] arguments);
/// <summary>Invoke the method.</summary>
/// <param name="arguments">The method arguments to pass in.</param>

View File

@ -17,10 +17,10 @@ namespace StardewModdingAPI
** Public methods
*********/
/// <summary>Get the property value.</summary>
TValue? GetValue();
TValue GetValue();
/// <summary>Set the property value.</summary>
//// <param name="value">The value to set.</param>
void SetValue(TValue? value);
void SetValue(TValue value);
}
}

View File

@ -806,7 +806,7 @@ namespace StardewModdingAPI.Metadata
if (door?.Sprite == null)
continue;
string? curKey = this.Reflection.GetField<string>(door.Sprite, "textureName").GetValue();
string? curKey = this.Reflection.GetField<string?>(door.Sprite, "textureName").GetValue();
if (this.IsSameBaseName(assetName, curKey))
door.Sprite.texture = texture.Value;
}
@ -1002,7 +1002,7 @@ namespace StardewModdingAPI.Metadata
GameLocation adventureGuild = Game1.getLocationFromName("AdventureGuild");
if (adventureGuild != null)
{
NPC? gil = this.Reflection.GetField<NPC>(adventureGuild, "Gil").GetValue();
NPC? gil = this.Reflection.GetField<NPC?>(adventureGuild, "Gil").GetValue();
if (gil != null)
characters.Add(new { Npc = gil, AssetName = gilKey });
}
@ -1031,7 +1031,7 @@ namespace StardewModdingAPI.Metadata
foreach (Farmer player in players)
{
this.Reflection.GetField<Dictionary<string, Dictionary<int, List<int>>>>(typeof(FarmerRenderer), "_recolorOffsets").GetValue()?.Remove(player.getTexture());
this.Reflection.GetField<Dictionary<string, Dictionary<int, List<int>>>?>(typeof(FarmerRenderer), "_recolorOffsets").GetValue()?.Remove(player.getTexture());
player.FarmerRenderer.MarkSpriteDirty();
}
@ -1049,15 +1049,19 @@ namespace StardewModdingAPI.Metadata
foreach (GameLocation location in this.GetLocations(buildingInteriors: false))
{
// get suspension bridges field
var field = this.Reflection.GetField<IEnumerable<SuspensionBridge>>(location, nameof(IslandNorth.suspensionBridges), required: false);
var field = this.Reflection.GetField<IEnumerable<SuspensionBridge>?>(location, nameof(IslandNorth.suspensionBridges), required: false);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse -- field is nullable when required: false
if (field == null || !typeof(IEnumerable<SuspensionBridge>).IsAssignableFrom(field.FieldInfo.FieldType))
continue;
// update textures
foreach (SuspensionBridge bridge in field.GetValue()!)
IEnumerable<SuspensionBridge>? bridges = field.GetValue();
if (bridges != null)
{
foreach (SuspensionBridge bridge in bridges)
this.Reflection.GetField<Texture2D>(bridge, "_texture").SetValue(texture.Value);
}
}
return texture.IsValueCreated;
}
@ -1134,7 +1138,7 @@ namespace StardewModdingAPI.Metadata
{
// reload schedule
this.Reflection.GetField<bool>(villager, "_hasLoadedMasterScheduleData").SetValue(false);
this.Reflection.GetField<Dictionary<string, string>>(villager, "_masterScheduleData").SetValue(null);
this.Reflection.GetField<Dictionary<string, string>?>(villager, "_masterScheduleData").SetValue(null);
villager.Schedule = villager.getSchedule(Game1.dayOfMonth);
// switch to new schedule if needed
@ -1161,7 +1165,7 @@ namespace StardewModdingAPI.Metadata
Game1.samBandName = content.LoadString("Strings/StringsFromCSFiles:Game1.cs.2156");
Game1.elliottBookName = content.LoadString("Strings/StringsFromCSFiles:Game1.cs.2157");
string[] dayNames = this.Reflection.GetField<string[]>(typeof(Game1), "_shortDayDisplayName").GetValue()!;
string[] dayNames = this.Reflection.GetField<string[]>(typeof(Game1), "_shortDayDisplayName").GetValue();
dayNames[0] = content.LoadString("Strings/StringsFromCSFiles:Game1.cs.3042");
dayNames[1] = content.LoadString("Strings/StringsFromCSFiles:Game1.cs.3043");
dayNames[2] = content.LoadString("Strings/StringsFromCSFiles:Game1.cs.3044");