patterncsharpMinor
Discriminated-unions in C#
Viewed 0 times
discriminatedunionsstackoverflow
Problem
So I really want to have something similar to discriminated unions in C#.
One way to do it is to use a visitor pattern, but it takes half a life to write all broilerplate code by hands.
There is another way that would allow me writing a bit less code, but it is based on delegates.
Consider the analogue of Options from F#:
-
E
One way to do it is to use a visitor pattern, but it takes half a life to write all broilerplate code by hands.
There is another way that would allow me writing a bit less code, but it is based on delegates.
Consider the analogue of Options from F#:
public abstract class Optional
{
public abstract TResult Resolve(Func someHandler, Func noneHandler);
}
public class Some : Optional
{
public Some(TValue value)
{
this.Value = value;
}
public TValue Value { get; private set; }
public override TResult Resolve(Func someHandler, Func noneHandler)
{
return someHandler(this.Value);
}
}
public class None : Optional
{
public None(String message)
{
this.Message = message;
}
public String Message { get; private set; }
public override TResult Resolve(Func someHandler, Func noneHandler)
{
return noneHandler(this.Message);
}
}
public class Demo {
public Optional ParseAbsoluteUri(String whateverUrl)
{
if (Uri.IsWellFormedUriString(whateverUrl, UriKind.Absolute))
{
var uri = new Uri(whateverUrl, UriKind.Absolute);
return new Some(uri);
}
else
{
return new None("Given URL is not absolute.");
}
}
public String ProcessUrl(String whateverUrl)
{
var uriOpt = this.ParseAbsoluteUri(whateverUrl);
var result = uriOpt.Resolve(uri => "Hey, your URL \"" + uri + "\" looks nice!", message => "Sorry, the URI that you gave looks bad: " + message);
return result;
}
public void Test()
{
Trace.WriteLine(this.ProcessUrl("http://google.com"));
Trace.WriteLine(this.ProcessUrl("Not url at all"));
/* output:
Hey, your URL "http://google.com/" looks nice!
Sorry, the URI that you gave looks bad: Given URL is not absolute.
*/
}
}-
E
Solution
This looks very well crafted. I don't know f# and I'm not really into functional programming, but I can enumerate everything I like about this code:
Well as I enumerated these points I did find a few minor nitpicks:
And as I enumerated these minor nitpicks I did find one tiny little thing that could be improved: the
...and this is where I'm clashing with
- Type parameter names are descriptive:
TValueandTResultare perfect.
- The interface for
Optionalis segregated; it's very focused and specialized, which makes it highly reusable... which is a nice feature for anabstractclass.
- Usage of
thisqualifier is consistent.
Well as I enumerated these points I did find a few minor nitpicks:
- Usage of
thisqualifier is redundant.
- Usage of
Stringcould be replaced with C# language aliasstring(but then again usage ofStringis beautifully consistent).
And as I enumerated these minor nitpicks I did find one tiny little thing that could be improved: the
Message property in the derived types is only assigned through the constructor, using the private setter. I'd make it readonly and change the auto-property for a get-only property:public None(String message)
{
_message = message;
}
private readonly String _message;
public String Message { get { return _message; } }...and this is where I'm clashing with
this - I prefer prefixing private fields with an underscore and avoid this altogether, you might have it like this instead:public None(String message)
{
this.message = message;
}
private readonly String message;
public String Message { get { return this.message; } }Code Snippets
public None(String message)
{
_message = message;
}
private readonly String _message;
public String Message { get { return _message; } }public None(String message)
{
this.message = message;
}
private readonly String message;
public String Message { get { return this.message; } }Context
StackExchange Code Review Q#31864, answer score: 3
Revisions (0)
No revisions yet.