HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Simple pack Uri builder

Submitted by: @import:stackexchange-codereview··
0
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 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

"Path must start with \"/\"."

Can become

@"Path must start with ""/""."

get only properties

private string _path;
public string RelativePath => _path;


Can become

public string RelativePath { get; }


get only properties, without a backing field

You 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 variable

Redundant 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 Dictionary

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.");
}


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.