Replacing Uri with a more convenient class
I needed some data structure for holding Uris so I thought I try the Uri
class. It quickly turned out that it's very impractical because:
- it's missing an implicit cast from/to string
- it doesn't automatically recognize uris as absolute or relative without specifying the
UriKind
- it doesn't parse the query-string so it cannot compare uris reliably when key-value pairs are in different order
- it's not easy to combine an absolute uri with a relative one
Working with it is just too inconvenient. As a solution I created my own SimpleUri
that should solve these issues. It doesn't support everything yet because I don't need it right now but adding a couple of more regexes later should not be a problem.
public class SimpleUri : IEquatable<SimpleUri>, IEquatable<string>
{
// https://regex101.com/r/sd288W/1
// using 'new' for _nicer_ syntax
private static readonly string UriPattern = string.Join(string.Empty, new
{
/* language=regexp */ @"^(?:(?<scheme>w+):)?",
/* language=regexp */ @"(?://(?<authority>w+))?",
/* language=regexp */ @"(?<path>[a-z0-9/:]+)",
/* language=regexp */ @"(?:?(?<query>[a-z0-9=&]+))?",
/* language=regexp */ @"(?:#(?<fragment>[a-z0-9]+))?"
});
public static readonly IEqualityComparer<SimpleUri> Comparer = EqualityComparerFactory<SimpleUri>.Create
(
equals: (x, y) => StringComparer.OrdinalIgnoreCase.Equals(x, y),
getHashCode: (obj) => StringComparer.OrdinalIgnoreCase.GetHashCode(obj)
);
public SimpleUri([NotNull] string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
var uriMatch = Regex.Match
(
uri,
UriPattern,
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
);
if (!uriMatch.Success)
{
throw new ArgumentException(paramName: nameof(uri), message: $"'{uri}' is not a valid Uri.");
}
Scheme = uriMatch.Groups["scheme"];
Authority = uriMatch.Groups["authority"];
Path = uriMatch.Groups["path"];
Query =
uriMatch.Groups["query"].Success
? Regex
.Matches
(
uriMatch.Groups["query"].Value,
@"(?:^|&)(?<key>[a-z0-9]+)(?:=(?<value>[a-z0-9]+))?",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
)
.Cast<Match>()
.ToImmutableDictionary
(
m => (ImplicitString)m.Groups["key"],
m => (ImplicitString)m.Groups["value"]
)
: ImmutableDictionary<ImplicitString, ImplicitString>.Empty;
Fragment = uriMatch.Groups["fragment"];
}
public SimpleUri(SimpleUri absoluteUri, SimpleUri relativeUri)
{
if (absoluteUri.IsRelative) throw new ArgumentException($"{nameof(absoluteUri)} must be an absolute Uri.");
if (!relativeUri.IsRelative) throw new ArgumentException($"{nameof(relativeUri)} must be a relative Uri.");
Scheme = absoluteUri.Scheme;
Authority = absoluteUri.Authority;
Path = absoluteUri.Path.Value.TrimEnd('/') + "/" + relativeUri.Path.Value.TrimStart('/');
Query = absoluteUri.Query;
Fragment = absoluteUri.Fragment;
}
public ImplicitString Scheme { get; }
public ImplicitString Authority { get; }
public ImplicitString Path { get; }
public IImmutableDictionary<ImplicitString, ImplicitString> Query { get; }
public ImplicitString Fragment { get; }
public bool IsRelative => !Scheme;
public override string ToString() => string.Join(string.Empty, GetComponents());
private IEnumerable<string> GetComponents()
{
if (Scheme)
{
yield return $"{Scheme}:";
}
if (Authority)
{
yield return $"//{Authority}";
}
yield return Path;
if (Query.Any())
{
var queryPairs =
Query
.OrderBy(x => (string)x.Key, StringComparer.OrdinalIgnoreCase)
.Select(x => $"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}");
yield return $"?{string.Join("&", queryPairs)}";
}
if (Fragment)
{
yield return $"#{Fragment}";
}
}
#region IEquatable
public bool Equals(SimpleUri other) => Comparer.Equals(this, other);
public bool Equals(string other) => Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is SimpleUri uri && Equals(uri);
public override int GetHashCode() => Comparer.GetHashCode(this);
#endregion
#region operators
public static implicit operator SimpleUri(string uri) => new SimpleUri(uri);
public static implicit operator string(SimpleUri uri) => uri.ToString();
public static SimpleUri operator +(SimpleUri absoluteUri, SimpleUri relativeUri) => new SimpleUri(absoluteUri, relativeUri);
#endregion
}
In this experiment I use a new helper for the first time which is the ImplicitString
. Its purpose is to be able to use a string
as a conditional without having to write any of the string.IsX
all over the place.
public class ImplicitString : IEquatable<ImplicitString>
{
public ImplicitString(string value) => Value = value;
[AutoEqualityProperty]
public string Value { get; }
public override string ToString() => Value;
public static implicit operator ImplicitString(string value) => new ImplicitString(value);
public static implicit operator ImplicitString(Group group) => group.Value;
public static implicit operator string(ImplicitString value) => value.ToString();
public static implicit operator bool(ImplicitString value) => !string.IsNullOrWhiteSpace(value);
#region IEquatable
public bool Equals(ImplicitString other) => AutoEquality<ImplicitString>.Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is ImplicitString str && Equals(str);
public override int GetHashCode() => AutoEquality<ImplicitString>.Comparer.GetHashCode(this);
#endregion
}
Example
I tested it with use-cases I currently need it for and it works fine:
new SimpleUri("scheme://authority/p/a/t/h?query#fragment").Dump();
new SimpleUri("scheme:p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h").Dump();
new SimpleUri("file:c:/p/a/t/h").Dump();
What do you say? Is this an optimal implementation or can it be improved?
c# parsing regex dto
add a comment |
I needed some data structure for holding Uris so I thought I try the Uri
class. It quickly turned out that it's very impractical because:
- it's missing an implicit cast from/to string
- it doesn't automatically recognize uris as absolute or relative without specifying the
UriKind
- it doesn't parse the query-string so it cannot compare uris reliably when key-value pairs are in different order
- it's not easy to combine an absolute uri with a relative one
Working with it is just too inconvenient. As a solution I created my own SimpleUri
that should solve these issues. It doesn't support everything yet because I don't need it right now but adding a couple of more regexes later should not be a problem.
public class SimpleUri : IEquatable<SimpleUri>, IEquatable<string>
{
// https://regex101.com/r/sd288W/1
// using 'new' for _nicer_ syntax
private static readonly string UriPattern = string.Join(string.Empty, new
{
/* language=regexp */ @"^(?:(?<scheme>w+):)?",
/* language=regexp */ @"(?://(?<authority>w+))?",
/* language=regexp */ @"(?<path>[a-z0-9/:]+)",
/* language=regexp */ @"(?:?(?<query>[a-z0-9=&]+))?",
/* language=regexp */ @"(?:#(?<fragment>[a-z0-9]+))?"
});
public static readonly IEqualityComparer<SimpleUri> Comparer = EqualityComparerFactory<SimpleUri>.Create
(
equals: (x, y) => StringComparer.OrdinalIgnoreCase.Equals(x, y),
getHashCode: (obj) => StringComparer.OrdinalIgnoreCase.GetHashCode(obj)
);
public SimpleUri([NotNull] string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
var uriMatch = Regex.Match
(
uri,
UriPattern,
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
);
if (!uriMatch.Success)
{
throw new ArgumentException(paramName: nameof(uri), message: $"'{uri}' is not a valid Uri.");
}
Scheme = uriMatch.Groups["scheme"];
Authority = uriMatch.Groups["authority"];
Path = uriMatch.Groups["path"];
Query =
uriMatch.Groups["query"].Success
? Regex
.Matches
(
uriMatch.Groups["query"].Value,
@"(?:^|&)(?<key>[a-z0-9]+)(?:=(?<value>[a-z0-9]+))?",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
)
.Cast<Match>()
.ToImmutableDictionary
(
m => (ImplicitString)m.Groups["key"],
m => (ImplicitString)m.Groups["value"]
)
: ImmutableDictionary<ImplicitString, ImplicitString>.Empty;
Fragment = uriMatch.Groups["fragment"];
}
public SimpleUri(SimpleUri absoluteUri, SimpleUri relativeUri)
{
if (absoluteUri.IsRelative) throw new ArgumentException($"{nameof(absoluteUri)} must be an absolute Uri.");
if (!relativeUri.IsRelative) throw new ArgumentException($"{nameof(relativeUri)} must be a relative Uri.");
Scheme = absoluteUri.Scheme;
Authority = absoluteUri.Authority;
Path = absoluteUri.Path.Value.TrimEnd('/') + "/" + relativeUri.Path.Value.TrimStart('/');
Query = absoluteUri.Query;
Fragment = absoluteUri.Fragment;
}
public ImplicitString Scheme { get; }
public ImplicitString Authority { get; }
public ImplicitString Path { get; }
public IImmutableDictionary<ImplicitString, ImplicitString> Query { get; }
public ImplicitString Fragment { get; }
public bool IsRelative => !Scheme;
public override string ToString() => string.Join(string.Empty, GetComponents());
private IEnumerable<string> GetComponents()
{
if (Scheme)
{
yield return $"{Scheme}:";
}
if (Authority)
{
yield return $"//{Authority}";
}
yield return Path;
if (Query.Any())
{
var queryPairs =
Query
.OrderBy(x => (string)x.Key, StringComparer.OrdinalIgnoreCase)
.Select(x => $"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}");
yield return $"?{string.Join("&", queryPairs)}";
}
if (Fragment)
{
yield return $"#{Fragment}";
}
}
#region IEquatable
public bool Equals(SimpleUri other) => Comparer.Equals(this, other);
public bool Equals(string other) => Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is SimpleUri uri && Equals(uri);
public override int GetHashCode() => Comparer.GetHashCode(this);
#endregion
#region operators
public static implicit operator SimpleUri(string uri) => new SimpleUri(uri);
public static implicit operator string(SimpleUri uri) => uri.ToString();
public static SimpleUri operator +(SimpleUri absoluteUri, SimpleUri relativeUri) => new SimpleUri(absoluteUri, relativeUri);
#endregion
}
In this experiment I use a new helper for the first time which is the ImplicitString
. Its purpose is to be able to use a string
as a conditional without having to write any of the string.IsX
all over the place.
public class ImplicitString : IEquatable<ImplicitString>
{
public ImplicitString(string value) => Value = value;
[AutoEqualityProperty]
public string Value { get; }
public override string ToString() => Value;
public static implicit operator ImplicitString(string value) => new ImplicitString(value);
public static implicit operator ImplicitString(Group group) => group.Value;
public static implicit operator string(ImplicitString value) => value.ToString();
public static implicit operator bool(ImplicitString value) => !string.IsNullOrWhiteSpace(value);
#region IEquatable
public bool Equals(ImplicitString other) => AutoEquality<ImplicitString>.Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is ImplicitString str && Equals(str);
public override int GetHashCode() => AutoEquality<ImplicitString>.Comparer.GetHashCode(this);
#endregion
}
Example
I tested it with use-cases I currently need it for and it works fine:
new SimpleUri("scheme://authority/p/a/t/h?query#fragment").Dump();
new SimpleUri("scheme:p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h").Dump();
new SimpleUri("file:c:/p/a/t/h").Dump();
What do you say? Is this an optimal implementation or can it be improved?
c# parsing regex dto
TheEqualityComparerFactory
can be found here.
– t3chb0t
Dec 16 at 18:07
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
FWIW I’m mildly surprised you didn’t extendURI
to createSimpleUri
. Surely it would be easier and more robust.
– RubberDuck
Dec 19 at 22:53
@RubberDuck I can still do this ;-] and I actually already was there but theUri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection.Uri
is more trouble than help.
– t3chb0t
2 days ago
add a comment |
I needed some data structure for holding Uris so I thought I try the Uri
class. It quickly turned out that it's very impractical because:
- it's missing an implicit cast from/to string
- it doesn't automatically recognize uris as absolute or relative without specifying the
UriKind
- it doesn't parse the query-string so it cannot compare uris reliably when key-value pairs are in different order
- it's not easy to combine an absolute uri with a relative one
Working with it is just too inconvenient. As a solution I created my own SimpleUri
that should solve these issues. It doesn't support everything yet because I don't need it right now but adding a couple of more regexes later should not be a problem.
public class SimpleUri : IEquatable<SimpleUri>, IEquatable<string>
{
// https://regex101.com/r/sd288W/1
// using 'new' for _nicer_ syntax
private static readonly string UriPattern = string.Join(string.Empty, new
{
/* language=regexp */ @"^(?:(?<scheme>w+):)?",
/* language=regexp */ @"(?://(?<authority>w+))?",
/* language=regexp */ @"(?<path>[a-z0-9/:]+)",
/* language=regexp */ @"(?:?(?<query>[a-z0-9=&]+))?",
/* language=regexp */ @"(?:#(?<fragment>[a-z0-9]+))?"
});
public static readonly IEqualityComparer<SimpleUri> Comparer = EqualityComparerFactory<SimpleUri>.Create
(
equals: (x, y) => StringComparer.OrdinalIgnoreCase.Equals(x, y),
getHashCode: (obj) => StringComparer.OrdinalIgnoreCase.GetHashCode(obj)
);
public SimpleUri([NotNull] string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
var uriMatch = Regex.Match
(
uri,
UriPattern,
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
);
if (!uriMatch.Success)
{
throw new ArgumentException(paramName: nameof(uri), message: $"'{uri}' is not a valid Uri.");
}
Scheme = uriMatch.Groups["scheme"];
Authority = uriMatch.Groups["authority"];
Path = uriMatch.Groups["path"];
Query =
uriMatch.Groups["query"].Success
? Regex
.Matches
(
uriMatch.Groups["query"].Value,
@"(?:^|&)(?<key>[a-z0-9]+)(?:=(?<value>[a-z0-9]+))?",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
)
.Cast<Match>()
.ToImmutableDictionary
(
m => (ImplicitString)m.Groups["key"],
m => (ImplicitString)m.Groups["value"]
)
: ImmutableDictionary<ImplicitString, ImplicitString>.Empty;
Fragment = uriMatch.Groups["fragment"];
}
public SimpleUri(SimpleUri absoluteUri, SimpleUri relativeUri)
{
if (absoluteUri.IsRelative) throw new ArgumentException($"{nameof(absoluteUri)} must be an absolute Uri.");
if (!relativeUri.IsRelative) throw new ArgumentException($"{nameof(relativeUri)} must be a relative Uri.");
Scheme = absoluteUri.Scheme;
Authority = absoluteUri.Authority;
Path = absoluteUri.Path.Value.TrimEnd('/') + "/" + relativeUri.Path.Value.TrimStart('/');
Query = absoluteUri.Query;
Fragment = absoluteUri.Fragment;
}
public ImplicitString Scheme { get; }
public ImplicitString Authority { get; }
public ImplicitString Path { get; }
public IImmutableDictionary<ImplicitString, ImplicitString> Query { get; }
public ImplicitString Fragment { get; }
public bool IsRelative => !Scheme;
public override string ToString() => string.Join(string.Empty, GetComponents());
private IEnumerable<string> GetComponents()
{
if (Scheme)
{
yield return $"{Scheme}:";
}
if (Authority)
{
yield return $"//{Authority}";
}
yield return Path;
if (Query.Any())
{
var queryPairs =
Query
.OrderBy(x => (string)x.Key, StringComparer.OrdinalIgnoreCase)
.Select(x => $"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}");
yield return $"?{string.Join("&", queryPairs)}";
}
if (Fragment)
{
yield return $"#{Fragment}";
}
}
#region IEquatable
public bool Equals(SimpleUri other) => Comparer.Equals(this, other);
public bool Equals(string other) => Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is SimpleUri uri && Equals(uri);
public override int GetHashCode() => Comparer.GetHashCode(this);
#endregion
#region operators
public static implicit operator SimpleUri(string uri) => new SimpleUri(uri);
public static implicit operator string(SimpleUri uri) => uri.ToString();
public static SimpleUri operator +(SimpleUri absoluteUri, SimpleUri relativeUri) => new SimpleUri(absoluteUri, relativeUri);
#endregion
}
In this experiment I use a new helper for the first time which is the ImplicitString
. Its purpose is to be able to use a string
as a conditional without having to write any of the string.IsX
all over the place.
public class ImplicitString : IEquatable<ImplicitString>
{
public ImplicitString(string value) => Value = value;
[AutoEqualityProperty]
public string Value { get; }
public override string ToString() => Value;
public static implicit operator ImplicitString(string value) => new ImplicitString(value);
public static implicit operator ImplicitString(Group group) => group.Value;
public static implicit operator string(ImplicitString value) => value.ToString();
public static implicit operator bool(ImplicitString value) => !string.IsNullOrWhiteSpace(value);
#region IEquatable
public bool Equals(ImplicitString other) => AutoEquality<ImplicitString>.Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is ImplicitString str && Equals(str);
public override int GetHashCode() => AutoEquality<ImplicitString>.Comparer.GetHashCode(this);
#endregion
}
Example
I tested it with use-cases I currently need it for and it works fine:
new SimpleUri("scheme://authority/p/a/t/h?query#fragment").Dump();
new SimpleUri("scheme:p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h").Dump();
new SimpleUri("file:c:/p/a/t/h").Dump();
What do you say? Is this an optimal implementation or can it be improved?
c# parsing regex dto
I needed some data structure for holding Uris so I thought I try the Uri
class. It quickly turned out that it's very impractical because:
- it's missing an implicit cast from/to string
- it doesn't automatically recognize uris as absolute or relative without specifying the
UriKind
- it doesn't parse the query-string so it cannot compare uris reliably when key-value pairs are in different order
- it's not easy to combine an absolute uri with a relative one
Working with it is just too inconvenient. As a solution I created my own SimpleUri
that should solve these issues. It doesn't support everything yet because I don't need it right now but adding a couple of more regexes later should not be a problem.
public class SimpleUri : IEquatable<SimpleUri>, IEquatable<string>
{
// https://regex101.com/r/sd288W/1
// using 'new' for _nicer_ syntax
private static readonly string UriPattern = string.Join(string.Empty, new
{
/* language=regexp */ @"^(?:(?<scheme>w+):)?",
/* language=regexp */ @"(?://(?<authority>w+))?",
/* language=regexp */ @"(?<path>[a-z0-9/:]+)",
/* language=regexp */ @"(?:?(?<query>[a-z0-9=&]+))?",
/* language=regexp */ @"(?:#(?<fragment>[a-z0-9]+))?"
});
public static readonly IEqualityComparer<SimpleUri> Comparer = EqualityComparerFactory<SimpleUri>.Create
(
equals: (x, y) => StringComparer.OrdinalIgnoreCase.Equals(x, y),
getHashCode: (obj) => StringComparer.OrdinalIgnoreCase.GetHashCode(obj)
);
public SimpleUri([NotNull] string uri)
{
if (uri == null) throw new ArgumentNullException(nameof(uri));
var uriMatch = Regex.Match
(
uri,
UriPattern,
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
);
if (!uriMatch.Success)
{
throw new ArgumentException(paramName: nameof(uri), message: $"'{uri}' is not a valid Uri.");
}
Scheme = uriMatch.Groups["scheme"];
Authority = uriMatch.Groups["authority"];
Path = uriMatch.Groups["path"];
Query =
uriMatch.Groups["query"].Success
? Regex
.Matches
(
uriMatch.Groups["query"].Value,
@"(?:^|&)(?<key>[a-z0-9]+)(?:=(?<value>[a-z0-9]+))?",
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
)
.Cast<Match>()
.ToImmutableDictionary
(
m => (ImplicitString)m.Groups["key"],
m => (ImplicitString)m.Groups["value"]
)
: ImmutableDictionary<ImplicitString, ImplicitString>.Empty;
Fragment = uriMatch.Groups["fragment"];
}
public SimpleUri(SimpleUri absoluteUri, SimpleUri relativeUri)
{
if (absoluteUri.IsRelative) throw new ArgumentException($"{nameof(absoluteUri)} must be an absolute Uri.");
if (!relativeUri.IsRelative) throw new ArgumentException($"{nameof(relativeUri)} must be a relative Uri.");
Scheme = absoluteUri.Scheme;
Authority = absoluteUri.Authority;
Path = absoluteUri.Path.Value.TrimEnd('/') + "/" + relativeUri.Path.Value.TrimStart('/');
Query = absoluteUri.Query;
Fragment = absoluteUri.Fragment;
}
public ImplicitString Scheme { get; }
public ImplicitString Authority { get; }
public ImplicitString Path { get; }
public IImmutableDictionary<ImplicitString, ImplicitString> Query { get; }
public ImplicitString Fragment { get; }
public bool IsRelative => !Scheme;
public override string ToString() => string.Join(string.Empty, GetComponents());
private IEnumerable<string> GetComponents()
{
if (Scheme)
{
yield return $"{Scheme}:";
}
if (Authority)
{
yield return $"//{Authority}";
}
yield return Path;
if (Query.Any())
{
var queryPairs =
Query
.OrderBy(x => (string)x.Key, StringComparer.OrdinalIgnoreCase)
.Select(x => $"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}");
yield return $"?{string.Join("&", queryPairs)}";
}
if (Fragment)
{
yield return $"#{Fragment}";
}
}
#region IEquatable
public bool Equals(SimpleUri other) => Comparer.Equals(this, other);
public bool Equals(string other) => Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is SimpleUri uri && Equals(uri);
public override int GetHashCode() => Comparer.GetHashCode(this);
#endregion
#region operators
public static implicit operator SimpleUri(string uri) => new SimpleUri(uri);
public static implicit operator string(SimpleUri uri) => uri.ToString();
public static SimpleUri operator +(SimpleUri absoluteUri, SimpleUri relativeUri) => new SimpleUri(absoluteUri, relativeUri);
#endregion
}
In this experiment I use a new helper for the first time which is the ImplicitString
. Its purpose is to be able to use a string
as a conditional without having to write any of the string.IsX
all over the place.
public class ImplicitString : IEquatable<ImplicitString>
{
public ImplicitString(string value) => Value = value;
[AutoEqualityProperty]
public string Value { get; }
public override string ToString() => Value;
public static implicit operator ImplicitString(string value) => new ImplicitString(value);
public static implicit operator ImplicitString(Group group) => group.Value;
public static implicit operator string(ImplicitString value) => value.ToString();
public static implicit operator bool(ImplicitString value) => !string.IsNullOrWhiteSpace(value);
#region IEquatable
public bool Equals(ImplicitString other) => AutoEquality<ImplicitString>.Comparer.Equals(this, other);
public override bool Equals(object obj) => obj is ImplicitString str && Equals(str);
public override int GetHashCode() => AutoEquality<ImplicitString>.Comparer.GetHashCode(this);
#endregion
}
Example
I tested it with use-cases I currently need it for and it works fine:
new SimpleUri("scheme://authority/p/a/t/h?query#fragment").Dump();
new SimpleUri("scheme:p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h?q1=v1&q2=v2&q3#fragment").Dump();
new SimpleUri("p/a/t/h").Dump();
new SimpleUri("file:c:/p/a/t/h").Dump();
What do you say? Is this an optimal implementation or can it be improved?
c# parsing regex dto
c# parsing regex dto
edited Dec 17 at 7:21
janos
97.1k12124350
97.1k12124350
asked Dec 16 at 18:03
t3chb0t
34k746111
34k746111
TheEqualityComparerFactory
can be found here.
– t3chb0t
Dec 16 at 18:07
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
FWIW I’m mildly surprised you didn’t extendURI
to createSimpleUri
. Surely it would be easier and more robust.
– RubberDuck
Dec 19 at 22:53
@RubberDuck I can still do this ;-] and I actually already was there but theUri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection.Uri
is more trouble than help.
– t3chb0t
2 days ago
add a comment |
TheEqualityComparerFactory
can be found here.
– t3chb0t
Dec 16 at 18:07
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
FWIW I’m mildly surprised you didn’t extendURI
to createSimpleUri
. Surely it would be easier and more robust.
– RubberDuck
Dec 19 at 22:53
@RubberDuck I can still do this ;-] and I actually already was there but theUri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection.Uri
is more trouble than help.
– t3chb0t
2 days ago
The
EqualityComparerFactory
can be found here.– t3chb0t
Dec 16 at 18:07
The
EqualityComparerFactory
can be found here.– t3chb0t
Dec 16 at 18:07
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
FWIW I’m mildly surprised you didn’t extend
URI
to create SimpleUri
. Surely it would be easier and more robust.– RubberDuck
Dec 19 at 22:53
FWIW I’m mildly surprised you didn’t extend
URI
to create SimpleUri
. Surely it would be easier and more robust.– RubberDuck
Dec 19 at 22:53
@RubberDuck I can still do this ;-] and I actually already was there but the
Uri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection. Uri
is more trouble than help.– t3chb0t
2 days ago
@RubberDuck I can still do this ;-] and I actually already was there but the
Uri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection. Uri
is more trouble than help.– t3chb0t
2 days ago
add a comment |
1 Answer
1
active
oldest
votes
Instead of this:
$"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}"
I would find it easier to understand this way:
$"{x.Key}{(x.Value ? $"={x.Value}" : string.Empty)}"
Instead of testing-by-printing, why not have proper unit tests for this?
(So I don't have to read the output after every change and re-convince myself that it's still good.)
I'm a bit surprised that the class doesn't handle URI with domain names containing a dot, for example https://stackoverflow.com/somepath
.
It might be an interesting feature to add,
when !uriMatch.Success
, to check if the URI could actually be parsed by the standard Uri
class.
That is, give a more clear signal to users of the class,
whether the URI is invalid, or it's just using some pattern not-yet-supported by SimpleUri
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209777%2freplacing-uri-with-a-more-convenient-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Instead of this:
$"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}"
I would find it easier to understand this way:
$"{x.Key}{(x.Value ? $"={x.Value}" : string.Empty)}"
Instead of testing-by-printing, why not have proper unit tests for this?
(So I don't have to read the output after every change and re-convince myself that it's still good.)
I'm a bit surprised that the class doesn't handle URI with domain names containing a dot, for example https://stackoverflow.com/somepath
.
It might be an interesting feature to add,
when !uriMatch.Success
, to check if the URI could actually be parsed by the standard Uri
class.
That is, give a more clear signal to users of the class,
whether the URI is invalid, or it's just using some pattern not-yet-supported by SimpleUri
.
add a comment |
Instead of this:
$"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}"
I would find it easier to understand this way:
$"{x.Key}{(x.Value ? $"={x.Value}" : string.Empty)}"
Instead of testing-by-printing, why not have proper unit tests for this?
(So I don't have to read the output after every change and re-convince myself that it's still good.)
I'm a bit surprised that the class doesn't handle URI with domain names containing a dot, for example https://stackoverflow.com/somepath
.
It might be an interesting feature to add,
when !uriMatch.Success
, to check if the URI could actually be parsed by the standard Uri
class.
That is, give a more clear signal to users of the class,
whether the URI is invalid, or it's just using some pattern not-yet-supported by SimpleUri
.
add a comment |
Instead of this:
$"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}"
I would find it easier to understand this way:
$"{x.Key}{(x.Value ? $"={x.Value}" : string.Empty)}"
Instead of testing-by-printing, why not have proper unit tests for this?
(So I don't have to read the output after every change and re-convince myself that it's still good.)
I'm a bit surprised that the class doesn't handle URI with domain names containing a dot, for example https://stackoverflow.com/somepath
.
It might be an interesting feature to add,
when !uriMatch.Success
, to check if the URI could actually be parsed by the standard Uri
class.
That is, give a more clear signal to users of the class,
whether the URI is invalid, or it's just using some pattern not-yet-supported by SimpleUri
.
Instead of this:
$"{x.Key}{(x.Value ? "=" : string.Empty)}{x.Value}"
I would find it easier to understand this way:
$"{x.Key}{(x.Value ? $"={x.Value}" : string.Empty)}"
Instead of testing-by-printing, why not have proper unit tests for this?
(So I don't have to read the output after every change and re-convince myself that it's still good.)
I'm a bit surprised that the class doesn't handle URI with domain names containing a dot, for example https://stackoverflow.com/somepath
.
It might be an interesting feature to add,
when !uriMatch.Success
, to check if the URI could actually be parsed by the standard Uri
class.
That is, give a more clear signal to users of the class,
whether the URI is invalid, or it's just using some pattern not-yet-supported by SimpleUri
.
answered Dec 17 at 7:44
janos
97.1k12124350
97.1k12124350
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209777%2freplacing-uri-with-a-more-convenient-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
The
EqualityComparerFactory
can be found here.– t3chb0t
Dec 16 at 18:07
Downvoted... how so?
– t3chb0t
Dec 17 at 12:49
FWIW I’m mildly surprised you didn’t extend
URI
to createSimpleUri
. Surely it would be easier and more robust.– RubberDuck
Dec 19 at 22:53
@RubberDuck I can still do this ;-] and I actually already was there but the
Uri
is not as great as one would think. It throws unexplained exceptions all over the place. Values are spread over several strange and seemingly redundant properties. I might use it later for some edge cases that I'm to lazy to implement myself but generally it's terrible. On top of it it has a super-confusing system for registering new parsers which will break any dependency-injection.Uri
is more trouble than help.– t3chb0t
2 days ago