Created
January 11, 2013 17:14
-
-
Save davidwhitney/4512395 to your computer and use it in GitHub Desktop.
A simpler way to parse strings in C# Parsing strings in C# can be verbose and horrible. The last thing you want to do when solving some real problem, is end up with a load of code extracting values from strings and marshalling them between data types. It’s silly, so lets not do it! Instead, I offer you an extension method and some tests. Do with…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class StringParsingNeedsToBeSimpler | |
{ | |
public void HereAreSomeExamples() | |
{ | |
//You know what sucks? | |
string value = "123"; | |
int outt; | |
if(!int.TryParse(value, out outt)) | |
{ | |
outt = 12345; // my default! | |
} | |
// That's ugly and verbose. | |
// So lets try these instead! | |
var betterWay = value.Parse(onFailure: () => 12345); | |
var evenBetter = value.Parse(() => 12345); | |
var youCanEvenDo = value.Parse<double>(); | |
var andCheckThisOut = "01/01/2012".Parse<DateTime>(); | |
var andThis = "01/01/2012".Parse<DateTime>(()=>DateTime.Now); | |
// Now isn't that a nice concise way to parse! | |
// Tests included below. | |
} | |
} | |
using System; | |
public static class TypeParsingExtensions | |
{ | |
public static object Parse(this string source, Type ttype, Func<object> onFailure = null) | |
{ | |
object parsed; | |
try | |
{ | |
parsed = Convert.ChangeType(source, ttype); | |
} | |
catch (Exception) | |
{ | |
if (onFailure == null) | |
{ | |
throw; | |
} | |
return onFailure(); | |
} | |
return parsed; | |
} | |
public static TType Parse<TType>(this string source, Func<TType> onFailure = null) | |
{ | |
return (TType)source.Parse(typeof(TType), onFailure != null ? (Func<object>)(() => onFailure()) : null); | |
} | |
} | |
using System; | |
using System.Collections.Generic; | |
using NUnit.Framework; | |
[TestFixture] | |
public class TypeParsingExtensionsTests | |
{ | |
private readonly List<TestCase> _testCases; | |
public TypeParsingExtensionsTests() | |
{ | |
_testCases = new List<TestCase> | |
{ | |
TestCase.For(validExample: 123, @default: 987), | |
TestCase.For(validExample: 123.54m, @default: 987.25m), | |
TestCase.For<float>(validExample: 123456800, @default: 987654321), | |
TestCase.For<byte>(validExample: 1, @default: 2), | |
TestCase.For(validExample: 123.456, @default: 543.321), | |
}; | |
} | |
// Tests use Parse(type) rather than Parse<type>() to keep them DRY (if slightly less clear). | |
[Test] | |
public void Parse_PassedValid_Parses() | |
{ | |
foreach (var testCase in _testCases) | |
{ | |
var output = testCase.Valid.Parse(testCase.TestType); | |
Assert.That(output, Is.EqualTo(testCase.Expectation)); | |
} | |
} | |
[Test] | |
public void Parse_PassedInvalid_ThrowsFormatException() | |
{ | |
foreach (var testCase in _testCases) | |
{ | |
Assert.Throws<FormatException>(() => testCase.Invalid.Parse(testCase.TestType)); | |
} | |
} | |
[Test] | |
public void Parse_PassedInvalidWithDefault_ReturnsDefault() | |
{ | |
foreach (var testCase in _testCases) | |
{ | |
var @case = testCase; | |
var output = testCase.Invalid.Parse(testCase.TestType, () => @case.Default); | |
Assert.That(output, Is.EqualTo(testCase.Default)); | |
} | |
} | |
private class TestCase | |
{ | |
public string Valid { get; private set; } | |
public string Invalid { get; private set; } | |
public object Expectation { get; private set; } | |
public object Default { get; private set; } | |
public Type TestType { get; private set; } | |
public static TestCase For<TType>(TType validExample, TType @default) | |
{ | |
return new TestCase(validExample.ToString()) { Expectation = validExample, Default = @default, TestType = typeof(TType) }; | |
} | |
private TestCase(string valid) | |
{ | |
Valid = valid; | |
Invalid = "Invalid"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment