patterncsharpMinor
Simple pack Uri builder
Viewed 0 times
builderurisimplepack
Problem
I want to make the creation of the pack Uri for WPF resources more verbose so they are easier to read and less error-prone and I thought I implement it using the builder pattern.
The base class for each builder (there are four of them) is the
(I omitted null checks to make is shorter).
```
abstract class PackUriBuilder
{
private string _path;
private UriKind _uriKind;
protected PackUriBuilder(string path)
{
if (!path.StartsWith("/")) throw new ArgumentException(paramName: nameof(path), message: "Path must start with \"/\".");
_path = path;
_uriKind = UriKind.Absolute;
}
public string Scheme => "pack";
public string RelativePath => _path;
public abstract string AbsolutePath { get; }
public static implicit operator string (PackUriBuilder builder) => builder.ToString();
public static implicit operator Uri(PackUriBuilder builder)
{
switch (builder._uriKind)
{
case UriKind.Absolute:
return new Uri(builder.ToString(), UriKind.Absolute);
case UriKind.Relative:
return new Uri(builder.RelativePath, UriKind.Relative);
}
// todo: I know this needs a better message ;-)
throw new ArgumentOutOfRangeException("Invalid UriKind.");
}
public override string ToString()
{
switch (_uriKind)
{
case UriKind.Absolute:
return AbsolutePath;
case UriKind.Relative:
return RelativePath;
}
// todo: I know this needs a better message ;-)
throw new ArgumentOutOfRangeException("Invalid UriKind.");
}
public Uri ToUri() => (Uri)this;
public PackUriBuilder Relative()
{
_uriKind = UriKind.Relat
The base class for each builder (there are four of them) is the
PackUriBuilder. It implements the UriKind logic, checks the path and requries the derived class to implement the AbsolutePath property. It also provides static methods to initialize each of the builders.(I omitted null checks to make is shorter).
```
abstract class PackUriBuilder
{
private string _path;
private UriKind _uriKind;
protected PackUriBuilder(string path)
{
if (!path.StartsWith("/")) throw new ArgumentException(paramName: nameof(path), message: "Path must start with \"/\".");
_path = path;
_uriKind = UriKind.Absolute;
}
public string Scheme => "pack";
public string RelativePath => _path;
public abstract string AbsolutePath { get; }
public static implicit operator string (PackUriBuilder builder) => builder.ToString();
public static implicit operator Uri(PackUriBuilder builder)
{
switch (builder._uriKind)
{
case UriKind.Absolute:
return new Uri(builder.ToString(), UriKind.Absolute);
case UriKind.Relative:
return new Uri(builder.RelativePath, UriKind.Relative);
}
// todo: I know this needs a better message ;-)
throw new ArgumentOutOfRangeException("Invalid UriKind.");
}
public override string ToString()
{
switch (_uriKind)
{
case UriKind.Absolute:
return AbsolutePath;
case UriKind.Relative:
return RelativePath;
}
// todo: I know this needs a better message ;-)
throw new ArgumentOutOfRangeException("Invalid UriKind.");
}
public Uri ToUri() => (Uri)this;
public PackUriBuilder Relative()
{
_uriKind = UriKind.Relat
Solution
Your code looks pretty got but there are some things that you can simplify, probably the switch cases are the most unwanted part of your code.
Verbatim strings
Can become
Can become
You can use expression bodies for all of your
Can become
You can do the same for all of the
Redundant casts
You already have an implicit operator that does that for you
Replacing the nasty
With a dictionary looking similar to this one
Can become
Your
Verbatim strings
"Path must start with \"/\"."Can become
@"Path must start with ""/""."get only propertiesprivate string _path;
public string RelativePath => _path;Can become
public string RelativePath { get; }get only properties, without a backing fieldYou can use expression bodies for all of your
get only properties, without a backing field:public override string AbsolutePath
{
get
{
return $"{Scheme}://application:,,,{RelativePath}";
}
}Can become
public override string AbsolutePath => $"{Scheme}://siteoforigin:,,,{RelativePath}";You can do the same for all of the
AbsolutePath properties.private string _assemblyShortName; can be a readonly variableRedundant casts
public Uri ToUri() => (Uri) this;You already have an implicit operator that does that for you
public static implicit operator Uri(PackUriBuilder builder)Replacing the nasty
switch case with a Dictionarypublic static implicit operator Uri(PackUriBuilder builder)
{
switch (builder._uriKind)
{
case UriKind.Absolute:
return new Uri(builder.ToString(), UriKind.Absolute);
case UriKind.Relative:
return new Uri(builder.RelativePath, UriKind.Relative);
}
// todo: I know this needs a better message ;-)
throw new ArgumentOutOfRangeException("Invalid UriKind.");
}With a dictionary looking similar to this one
protected static Dictionary> helper = new Dictionary
>
{
{UriKind.Absolute, builder => new Uri(builder.ToString(), UriKind.Absolute)},
{UriKind.Relative, builder => new Uri(builder.RelativePath, UriKind.Relative)}
};Can become
public static implicit operator Uri(PackUriBuilder builder) => helper[builder._uriKind].Invoke(builder);Your
public override string ToString() is similar but it might be a little bit more harder to do with a dictionary, since there are some virtual variables involved, namely AbsolutePath and since you can't make it into a static variable and initialize it like the helper dictionary used for the implicit operator, You might need to initialize the dictionary from the constructor but as you know virtual calls can be very tricky if called in the constructor.Code Snippets
private string _path;
public string RelativePath => _path;public string RelativePath { get; }public override string AbsolutePath
{
get
{
return $"{Scheme}://application:,,,{RelativePath}";
}
}public override string AbsolutePath => $"{Scheme}://siteoforigin:,,,{RelativePath}";public Uri ToUri() => (Uri) this;Context
StackExchange Code Review Q#150724, answer score: 9
Revisions (0)
No revisions yet.