C# WebAPI类变量跨类引用及WinForm汇率更新实现咨询
Hey there! Let's walk through building that exchange rate service for your Windows Forms app, and clear up how to share those rate values across multiple forms.
Since you need to fetch rates once at startup and reuse them across forms, a singleton class is perfect here—it ensures only one instance of the service exists, so you don't make duplicate API calls, and all forms can access the same rate data.
Here's a complete example of the service class:
using System; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; public class ExchangeRateService { // Singleton instance (only one exists app-wide) private static readonly ExchangeRateService _sharedInstance = new ExchangeRateService(); // Private fields to store the rates (only modifiable within this class) private decimal _gbpToEur; private decimal _eurToGbp; // Private constructor to prevent external instantiation private ExchangeRateService() {} // Public read-only properties to let other classes access the rates public decimal GbpToEurRate => _gbpToEur; public decimal EurToGbpRate => _eurToGbp; // Get the singleton instance public static ExchangeRateService GetInstance() { return _sharedInstance; } // Fetch latest rates from your Web API public async Task LoadLatestRatesAsync() { try { using var httpClient = new HttpClient(); // Replace with your actual API endpoint (adjust the JSON parsing to match your API's response) var apiResponse = await httpClient.GetStringAsync("https://your-exchange-api.com/latest?base=GBP"); // Parse the JSON response (using System.Text.Json here; Newtonsoft.Json works too) var rateData = JsonSerializer.Deserialize<ExchangeRateResponse>(apiResponse); // Update the private rate fields _gbpToEur = rateData.EurRate; _eurToGbp = Math.Round(1 / _gbpToEur, 4); // Calculate reverse rate } catch (Exception ex) { // Handle API errors (log, show a message, use fallback rates, etc.) Console.WriteLine($"Failed to load rates: {ex.Message}"); _gbpToEur = 1.17m; // Fallback rate if API fails _eurToGbp = 0.85m; } } // Helper class to match your API's JSON structure (adjust as needed) private class ExchangeRateResponse { [JsonPropertyName("rates")] public Rates Rates { get; set; } // Shortcut to get EUR rate directly public decimal EurRate => Rates.EUR; } private class Rates { [JsonPropertyName("EUR")] public decimal EUR { get; set; } } }
You want to fetch rates before your forms load, so update your Program.cs to run the async load method first:
using System; using System.Threading.Tasks; using System.Windows.Forms; static class Program { [STAThread] static async Task Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // Initialize the rate service and fetch latest data var rateService = ExchangeRateService.GetInstance(); await rateService.LoadLatestRatesAsync(); // Launch your main form Application.Run(new MainForm()); } }
Now any form in your app can grab the singleton instance and use the rates:
// Example in a conversion form private void ConvertButton_Click(object sender, EventArgs e) { var rateService = ExchangeRateService.GetInstance(); if (decimal.TryParse(AmountTextBox.Text, out decimal amount)) { decimal convertedAmount = FromCurrencyComboBox.SelectedItem.ToString() == "GBP" ? amount * rateService.GbpToEurRate : amount * rateService.EurToGbpRate; ResultLabel.Text = $"{amount} {FromCurrencyComboBox.SelectedItem} = {convertedAmount:F2} {ToCurrencyComboBox.SelectedItem}"; } }
To create variables in a class that other classes can access, follow these core principles:
- Encapsulate private data: Store the raw values in private fields (
_gbpToEur) so they can't be modified directly from outside the class—this keeps your rate data consistent. - Expose public read-only properties: Use
public decimal GbpToEurRate => _gbpToEur;to let other classes read the value without changing it. - Use a singleton or static class for global access: If you need the same data across the entire app, a singleton (like the example above) ensures all forms use the same rate values. Alternatively, you could use a static class, but singletons are better if you need to run initialization logic (like fetching from the API).
- Handle API failures: Always add error handling (like the
try/catchin the service) so your app doesn't crash if the API is down. - Add rate updates: If you want to refresh rates periodically, add a
Timerto the service class that callsLoadLatestRatesAsyncevery hour or so. - Thread safety: If you're updating rates while the app is running, use a
lockaround the rate fields to prevent race conditions (since Windows Forms uses a single UI thread, this is mostly needed if you're updating rates in background tasks).
内容的提问来源于stack exchange,提问作者Isabelle May

