6

Obviously it would be fairly simple to implement the following interfaces for your own solution

public interface IParsable<T>
{
    T Parse(string s);
}

public interface ITryParsable<T> : IParsable<T>
{
    bool TryParse(string s, out T output);
}

Having been writing various ways of parsing unknown typed user input data, I would have found having int, decimal, etc, etc implement a version of these interfaces indispensable.

To me it seems like a fairly obvious thing to have included in the System namespace.

Obviously this is not the case. So what is the best way of seeing whether a class "implements" these interfaces?

Checking whether the method exists via Duck Typing seems like a sensible alternative, but Reflection isn't terribly performant.

It looks like this is not possible as C# does not allow static methods in interfaces.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
dav_i
  • 27,509
  • 17
  • 104
  • 136
  • _"What is the best way of getting around this?"_ - if "this" is an interface missing in the base class library, then you have no other option than to manually write the interface. Can you try to explain your actual problem? I suppose you have a variable of some type, and you want to try to parse it as any other type and see which one works? – CodeCaster Dec 09 '13 at 14:20
  • 9
    Those are static methods (they create an instance, so on which instance would you call them?). Interfaces only support instance methods. – CodesInChaos Dec 09 '13 at 14:22
  • @CodesInChaos D'oh. Great point. – dav_i Dec 09 '13 at 14:24
  • "but Reflection isn't terribly performant." - With a bit of caching it's pretty fast. I've written [such a caching parser](http://stackoverflow.com/questions/4956575/assigning-type-at-runtime/4956763#4956763) – CodesInChaos Dec 09 '13 at 14:24
  • @CodesInChaos Thanks, looks good. *FEELING RATHER STUPID AT THE MOMENT* (it's Monday). – dav_i Dec 09 '13 at 14:29
  • FYI, I think you meant to ask why .NET doesn't have `IParsable`, not C#. – John Saunders Dec 09 '13 at 15:21
  • @CodesInChaos good news. With C# 11 static abstract methods can be added to an interface and `IParsable` is now a thing. – Keith Banner Nov 10 '22 at 20:35

2 Answers2

6

.NET 7 adds IParsable. It is now used in all of these types:

System.Byte
System.Char
System.DateOnly
System.DateTime
System.DateTimeOffset
System.Decimal
System.Double
System.Guid
System.Half
System.Int128
System.Int16
System.Int32
System.Int64
System.IntPtr
System.ISpanParsable<TSelf>
System.Numerics.BigInteger
System.Numerics.Complex
System.Numerics.IBinaryFloatingPointIeee754<TSelf>
System.Numerics.IBinaryInteger<TSelf>
System.Numerics.IBinaryNumber<TSelf>
System.Numerics.IExponentialFunctions<TSelf>
System.Numerics.IFloatingPoint<TSelf>
System.Numerics.IFloatingPointConstants<TSelf>
System.Numerics.IFloatingPointIeee754<TSelf>
System.Numerics.IHyperbolicFunctions<TSelf>
System.Numerics.ILogarithmicFunctions<TSelf>
System.Numerics.INumber<TSelf>
System.Numerics.INumberBase<TSelf>
System.Numerics.IPowerFunctions<TSelf>
System.Numerics.IRootFunctions<TSelf>
System.Numerics.ISignedNumber<TSelf>
System.Numerics.ITrigonometricFunctions<TSelf>
System.Numerics.IUnsignedNumber<TSelf>
System.Runtime.InteropServices.NFloat
System.SByte
System.Single
System.TimeOnly
System.TimeSpan
System.UInt128
System.UInt16
System.UInt32
System.UInt64
System.UIntPtr
Keith Banner
  • 602
  • 1
  • 10
  • 15
5

Since C# does not support static interfaces, you would have to have an instance of the object in order to call the parse method. You would end up with something like this:

var a = new int().Parse<int>("123");
var b = 123.Parse("567");

Or with the TryParse method things get even more weird:

int x;
if (x.TryParse("456", out x))
    // trippy... now imagine that x is a reference type...
MattDavey
  • 8,897
  • 3
  • 31
  • 54
  • `var p = default(int); p.Parse("567"); Console.WriteLine(p);` doesn't look *too* bad to me, though I do admit it's confusing enough that it probably isn't worth the effort. –  Dec 09 '13 at 14:30
  • @CodesInChaos the constructor parentheses were missing. Edited. – MattDavey Dec 09 '13 at 14:36
  • @hvd, if this is OK for you, you can always write the corresponding extension methods, as this will be possible in C# – Ivaylo Slavov Dec 09 '13 at 14:37
  • Even with parentheses the code makes no sense. Calling a generic `Parse` method on an instance of `Object`. How would that enable interfaces? – CodesInChaos Dec 09 '13 at 14:59
  • @IvayloSlavov It might be possible with extension methods (I'm not sure, can you have a `this ref` parameter for value types?), but it's not possible to add interfaces to built-in types, so the generic advantage wouldn't apply anyway. Edit: no, `this ref` is not valid, even for value types, so it's not possible, even with extension methods. –  Dec 09 '13 at 15:45
  • @hvd, I agree there will be no advantage because you will have to write extension methods for all types you need to have these methods on: `int` , `double` and etc. So you may have: `public static int Parse(this int @this, string value) { return int.Parse(value); }` The same for `int.TryParse` . I have never mentioned `this ref` in any way and I am unable to see your point on that. Sorry for misunderstanding, I'd be glad if you clarify. – Ivaylo Slavov Dec 10 '13 at 08:21
  • 1
    @IvayloSlavov In my example, I used `p.Parse("567");` which would modify `p`. This is possible with instance methods on `int`, but not with extension methods on `int`. –  Dec 10 '13 at 08:37
  • @hvd, I see what you had in mind then. Unfortunately, no, it will not be possible again, as `int` is an immutable type. The extension methods I spoke of will make possible for this to be valid: `default(int).Parse("567");` which will return another integer. In similar fashion `"abc234".Replace("3", "0")` will return another string instance. I seem to have missed the last line in your example `Console.WriteLine(p);` that subjects to mutability of `p`. – Ivaylo Slavov Dec 10 '13 at 08:58