patterncsharpMinor
Simple Service Locator
Viewed 0 times
locatorsimpleservice
Problem
I've created a small, strongly-typed generic Service Locator object for .NET 3.5.
It supports optional polymorphic service location and keyed services. I am looking for a general review, but especially looking for pointers on best practices I've missed or any awkwardness in the API.
This code can also be found as a public GitHub Repository
```
///
/// Simple service locator
///
public class ServiceLocator
{
#region Private Classes
///
/// Simple .NET 3.5 Tuple class.
///
/// The type of the first item.
/// The type of the second item.
[DebuggerDisplay("Item1: {Item1}, Item2: {Item2}")]
private class Tuple
{
#region Public Properties
public T Item1 { get; set; }
public V Item2 { get; set; }
#endregion Public Properties
#region Public Constructors
public Tuple(T item1, V item2)
{
Item1 = item1;
Item2 = item2;
}
#endregion Public Constructors
#region Public Methods
///
/// Determines whether the specified , is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
var objAsTuple = obj as Tuple;
return objAsTuple != null && IsEqualTo(objAsTuple.Item1, Item1) && IsEqualTo(objAsTuple.Item2, Item2);
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
unchecked
{
var item1HashCode = Item1 == null ? 0 : Item1.GetHashCode();
var item2HashCode = Item2 == null ? 0 : Item2.GetHashCode();
retu
It supports optional polymorphic service location and keyed services. I am looking for a general review, but especially looking for pointers on best practices I've missed or any awkwardness in the API.
This code can also be found as a public GitHub Repository
```
///
/// Simple service locator
///
public class ServiceLocator
{
#region Private Classes
///
/// Simple .NET 3.5 Tuple class.
///
/// The type of the first item.
/// The type of the second item.
[DebuggerDisplay("Item1: {Item1}, Item2: {Item2}")]
private class Tuple
{
#region Public Properties
public T Item1 { get; set; }
public V Item2 { get; set; }
#endregion Public Properties
#region Public Constructors
public Tuple(T item1, V item2)
{
Item1 = item1;
Item2 = item2;
}
#endregion Public Constructors
#region Public Methods
///
/// Determines whether the specified , is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object obj)
{
var objAsTuple = obj as Tuple;
return objAsTuple != null && IsEqualTo(objAsTuple.Item1, Item1) && IsEqualTo(objAsTuple.Item2, Item2);
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
unchecked
{
var item1HashCode = Item1 == null ? 0 : Item1.GetHashCode();
var item2HashCode = Item2 == null ? 0 : Item2.GetHashCode();
retu
Solution
Regions
Please read are-regions-an-antipattern-or-code-smell
Is there a good use for regions?
No. There was a legacy use: generated code. Still, code generation
tools just have to use partial classes instead. If C# has regions
support, it's mostly because this legacy use, and because now that too
many people used regions in their code, it would be impossible to
remove them without breaking existent codebases.
Think about it as about goto. The fact that the language or the IDE
supports a feature doesn't mean that it should be used daily. StyleCop
SA1124 rule is clear: you should not use regions. Never.
Instead of using the
Please see: what-is-more-efficient-dictionary-trygetvalue-or-containskeyitem
TryGetValue will be faster.
ContainsKey uses the same check as TryGetValue, which internally
refers to the actual entry location. The Item property actually has
nearly identical code functionality as TryGetValue, except that it
will throw an exception instead of returning false.
Using ContainsKey followed by the item basically duplicates the lookup
functionality, which is the bulk of the computation in this case.
In the
you should remove the
Conclusion
Setting aside the points mentioned above:
-
your xml documentations looks pretty good, I couldn't find any flaw in them (quick glance).
-
your code is well structured and readable
Please read are-regions-an-antipattern-or-code-smell
Is there a good use for regions?
No. There was a legacy use: generated code. Still, code generation
tools just have to use partial classes instead. If C# has regions
support, it's mostly because this legacy use, and because now that too
many people used regions in their code, it would be impossible to
remove them without breaking existent codebases.
Think about it as about goto. The fact that the language or the IDE
supports a feature doesn't mean that it should be used daily. StyleCop
SA1124 rule is clear: you should not use regions. Never.
Instead of using the
Dictionary.ContainsKey() method you should better use TryGetValue(). Please see: what-is-more-efficient-dictionary-trygetvalue-or-containskeyitem
TryGetValue will be faster.
ContainsKey uses the same check as TryGetValue, which internally
refers to the actual entry location. The Item property actually has
nearly identical code functionality as TryGetValue, except that it
will throw an exception instead of returning false.
Using ContainsKey followed by the item basically duplicates the lookup
functionality, which is the bulk of the computation in this case.
In the
Unregiser() method public static void Unregister(T service, object key) where T : class
{
var type = typeof(T);
var dictKey = new Tuple(type, key);
if (!Instance.services.ContainsKey(dictKey))
{
throw new KeyNotFoundException(string.Format("Could not find a service of type {0} with key {1}", type, key));
}
Instance.services.Remove(dictKey);
}you should remove the
ContainsKey() call and use the returned value of the Remove() call instead like so public static void Unregister(T service, object key) where T : class
{
var type = typeof(T);
var dictKey = new Tuple(type, key);
if (Instance.services.Remove(dictKey)) { return; }
throw new KeyNotFoundException(string.Format("Could not find a service of type {0} with key {1}", type, key));
}Conclusion
Setting aside the points mentioned above:
-
your xml documentations looks pretty good, I couldn't find any flaw in them (quick glance).
-
your code is well structured and readable
Code Snippets
public static void Unregister<T>(T service, object key) where T : class
{
var type = typeof(T);
var dictKey = new Tuple<Type, object>(type, key);
if (!Instance.services.ContainsKey(dictKey))
{
throw new KeyNotFoundException(string.Format("Could not find a service of type {0} with key {1}", type, key));
}
Instance.services.Remove(dictKey);
}public static void Unregister<T>(T service, object key) where T : class
{
var type = typeof(T);
var dictKey = new Tuple<Type, object>(type, key);
if (Instance.services.Remove(dictKey)) { return; }
throw new KeyNotFoundException(string.Format("Could not find a service of type {0} with key {1}", type, key));
}Context
StackExchange Code Review Q#93869, answer score: 7
Revisions (0)
No revisions yet.