.NET Standard 1.6中TypeConverter替代方案及类型转换异常处理
Alright, let's work through this problem—since TypeConverter isn't available in .NET Standard 1.6, we need solid alternatives to replace try/catch for checking if a string can be converted to your generic type T in the GetData<T> method. Here are a few practical approaches you can implement:
1. Explicit TryParse Checks for Common Value Types
For basic value types like int, bool, DateTime, etc., you can directly check the type of T and call the corresponding TryParse method. This is straightforward and avoids reflection overhead.
internal static T GetData<T>(string input, T defaultValue) { // Handle int conversions if (typeof(T) == typeof(int)) { if (int.TryParse(input, out int result)) return (T)(object)result; } // Handle bool conversions else if (typeof(T) == typeof(bool)) { if (bool.TryParse(input, out bool result)) return (T)(object)result; } // Add other common types as needed: long, double, DateTime, Guid, etc. else if (typeof(T) == typeof(DateTime)) { if (DateTime.TryParse(input, out DateTime result)) return (T)(object)result; } // Fallback if conversion fails or type isn't explicitly handled return defaultValue; }
Pros: Fast, no reflection overhead, easy to debug.
Cons: Requires manual updates to support new types—you'll need to add an else if block for every type you want to handle.
2. Reflectively Invoke TryParse (Automatic Support for Compatible Types)
If you want to automatically support any type that has a static TryParse(string, out T) method (which most built-in value types do), you can use reflection to locate and call this method. This avoids manually coding each type.
internal static T GetData<T>(string input, T defaultValue) { // Look for a static TryParse method with the signature: bool TryParse(string, out T) var tryParseMethod = typeof(T).GetMethod( "TryParse", new[] { typeof(string), typeof(T).MakeByRefType() } ); if (tryParseMethod != null) { object[] parameters = new object[] { input, null }; bool conversionSuccess = (bool)tryParseMethod.Invoke(null, parameters); if (conversionSuccess) { return (T)parameters[1]; } } // Handle enums separately (since Enum.TryParse is on the Enum class, not the enum type itself) if (typeof(T).IsEnum) { if (Enum.TryParse(input, out T enumResult)) { return enumResult; } } // Fallback for unsupported types or failed conversions return defaultValue; }
Pros: Automatically supports any type with a matching TryParse method; no manual type additions needed.
Cons: Minor reflection overhead (though this is negligible for most use cases, and still cheaper than catching exceptions on failure paths).
3. Custom Convertible Interface for Complex/Custom Types
If you need to support custom types that don't have a TryParse method, create a dedicated interface for string-to-type conversion. This gives you full control over how custom types are converted.
First, define the interface:
public interface IStringConvertible<T> { bool TryConvertFromString(string input, out T result); }
Then implement it in your custom type:
public class UserId : IStringConvertible<UserId> { public int Value { get; private set; } private UserId(int value) => Value = value; public bool TryConvertFromString(string input, out UserId result) { result = null; if (int.TryParse(input, out int intValue) && intValue > 0) { result = new UserId(intValue); return true; } return false; } }
Update your GetData<T> method to check for this interface:
internal static T GetData<T>(string input, T defaultValue) { // First check for TryParse as in approach 2 var tryParseMethod = typeof(T).GetMethod( "TryParse", new[] { typeof(string), typeof(T).MakeByRefType() } ); if (tryParseMethod != null) { object[] parameters = new object[] { input, null }; bool conversionSuccess = (bool)tryParseMethod.Invoke(null, parameters); if (conversionSuccess) { return (T)parameters[1]; } } // Handle enums if (typeof(T).IsEnum) { if (Enum.TryParse(input, out T enumResult)) { return enumResult; } } // Check for custom convertible interface var convertibleInterface = typeof(IStringConvertible<>).MakeGenericType(typeof(T)); if (convertibleInterface.IsAssignableFrom(typeof(T))) { var convertMethod = convertibleInterface.GetMethod("TryConvertFromString"); if (convertMethod != null) { object[] parameters = new object[] { input, null }; bool conversionSuccess = (bool)convertMethod.Invoke(null, parameters); if (conversionSuccess) { return (T)parameters[1]; } } } return defaultValue; }
Pros: Full control over custom type conversions; clean, extensible pattern.
Cons: Requires modifying custom types to implement the interface.
Final Notes
Choose the approach that best fits your use case:
- Use approach 1 if you only need to support a small, fixed set of basic types.
- Use approach 2 for broad support of built-in types without manual coding.
- Use approach 3 alongside the others if you need to handle custom complex types.
All these methods avoid relying on try/catch for conversion checks, which is more performant and cleaner than exception-based logic for expected failure cases.
内容的提问来源于stack exchange,提问作者Parsa

