Something that comes up quite a lot in my current work is that there is a generalised process that needs to happen, but then the odd part of that process needs to happen slightly differently depending on the value of a certain variable, and I'm not quite sure what's the most elegant way to handle this.
I'll use the example that we usually have, which is doing things slightly differently depending on the country we're dealing with.
So I have a class, let's call it Processor:
public class Processor
{
public string Process(string country, string text)
{
text.Capitalise();
text.RemovePunctuation();
text.Replace("é", "e");
var split = text.Split(",");
string.Join("|", split);
}
}
Except that only some of those actions need to happen for certain countries. For example, only 6 countries require the capitalisation step. The character to split on might change depending on the country. Replacing the accented 'e' might only be required depending on the country.
Obviously you could solve it by doing something like this:
public string Process(string country, string text)
{
if (country == "USA" || country == "GBR")
{
text.Capitalise();
}
if (country == "DEU")
{
text.RemovePunctuation();
}
if (country != "FRA")
{
text.Replace("é", "e");
}
var separator = DetermineSeparator(country);
var split = text.Split(separator);
string.Join("|", split);
}
But when you're dealing with all the possible countries in the world, that becomes very cumbersome. And regardless, the if statements make the logic harder to read (at least, if you imagine a more complex method than the example), and the cyclomatic complexity starts to creep up pretty fast.
So at the moment I'm sort of doing something like this:
public class Processor
{
CountrySpecificHandlerFactory handlerFactory;
public Processor(CountrySpecificHandlerFactory handlerFactory)
{
this.handlerFactory = handlerFactory;
}
public string Process(string country, string text)
{
var handlers = this.handlerFactory.CreateHandlers(country);
handlers.Capitalier.Capitalise(text);
handlers.PunctuationHandler.RemovePunctuation(text);
handlers.SpecialCharacterHandler.ReplaceSpecialCharacters(text);
var separator = handlers.SeparatorHandler.DetermineSeparator();
var split = text.Split(separator);
string.Join("|", split);
}
}
Handlers:
public class CountrySpecificHandlerFactory
{
private static IDictionary<string, ICapitaliser> capitaliserDictionary
= new Dictionary<string, ICapitaliser>
{
{ "USA", new Capitaliser() },
{ "GBR", new Capitaliser() },
{ "FRA", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
{ "DEU", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
};
// Imagine the other dictionaries like this...
public CreateHandlers(string country)
{
return new CountrySpecificHandlers
{
Capitaliser = capitaliserDictionary[country],
PunctuationHanlder = punctuationDictionary[country],
// etc...
};
}
}
public class CountrySpecificHandlers
{
public ICapitaliser Capitaliser { get; private set; }
public IPunctuationHanlder PunctuationHanlder { get; private set; }
public ISpecialCharacterHandler SpecialCharacterHandler { get; private set; }
public ISeparatorHandler SeparatorHandler { get; private set; }
}
Which equally I'm not really sure I like. The logic is still somewhat obscured by all of the factory creation and you can't simply look at the original method and see what happens when a "GBR" process is executed, for example. You also end up creating a lot of classes (in more complex examples than this) in the style GbrPunctuationHandler, UsaPunctuationHandler, etc... which means that you have to look at several different classes to figure out all of the possible actions that could happen during punctuation handling. Obviously I don't want one giant class with a billion if statements, but equally 20 classes with slightly differing logic also feels clunky.
Basically I think I've got myself into some sort of OOP knot and don't quite know a good way of untangling it. I was wondering if there was a pattern out there that would help with this type of process?
I would suggest encapsulating all options in one class:
public class ProcessOptions
{
public bool Capitalise { get; set; }
public bool RemovePunctuation { get; set; }
public bool Replace { get; set; }
public char ReplaceChar { get; set; }
public char ReplacementChar { get; set; }
public bool SplitAndJoin { get; set; }
public char JoinChar { get; set; }
public char SplitChar { get; set; }
}
and pass it into the Process method:
public string Process(ProcessOptions options, string text)
{
if(options.Capitalise)
text.Capitalise();
if(options.RemovePunctuation)
text.RemovePunctuation();
if(options.Replace)
text.Replace(options.ReplaceChar, options.ReplacementChar);
if(options.SplitAndJoin)
{
var split = text.Split(options.SplitChar);
return string.Join(options.JoinChar, split);
}
return text;
}
When the .NET framework set out to handle these sorts of problems, it didn't model everything as string. So you have, for instance, the CultureInfo class:
Provides information about a specific culture (called a locale for unmanaged code development). The information includes the names for the culture, the writing system, the calendar used, the sort order of strings, and formatting for dates and numbers.
Now, this class may not contain the specific features that you need, but you can obviously create something analogous. And then you change your Process method:
public string Process(CountryInfo country, string text)
Your CountryInfo class can then have a bool RequiresCapitalization property, etc, that helps your Process method direct its processing appropriately.
Maybe you could have one Processor per country?
public class FrProcessor : Processor {
protected override string Separator => ".";
protected override string ProcessSpecific(string text) {
return text.Replace("é", "e");
}
}
public class UsaProcessor : Processor {
protected override string Separator => ",";
protected override string ProcessSpecific(string text) {
return text.Capitalise().RemovePunctuation();
}
}
And one base class to handle common parts of the processing:
public abstract class Processor {
protected abstract string Separator { get; }
protected virtual string ProcessSpecific(string text) { }
private string ProcessCommon(string text) {
var split = text.Split(Separator);
return string.Join("|", split);
}
public string Process(string text) {
var s = ProcessSpecific(text);
return ProcessCommon(s);
}
}
Also, you should rework your return types because it won't compile as you wrote them - sometimes a string method doesn't return anything.
You can create a common interface with a Process method...
public interface IProcessor
{
string Process(string text);
}
Then you implement it for each country...
public class Processors
{
public class GBR : IProcessor
{
public string Process(string text)
{
return $"{text} (processed with GBR rules)";
}
}
public class FRA : IProcessor
{
public string Process(string text)
{
return $"{text} (processed with FRA rules)";
}
}
}
You can then create a common method for instantiating and executing each country related class...
// also place these in the Processors class above
public static IProcessor CreateProcessor(string country)
{
var typeName = $"{typeof(Processors).FullName}+{country}";
var processor = (IProcessor)Assembly.GetAssembly(typeof(Processors)).CreateInstance(typeName);
return processor;
}
public static string Process(string country, string text)
{
var processor = CreateProcessor(country);
return processor?.Process(text);
}
Then you just need to create and use the processors like so...
// create a processor object for multiple use, if needed...
var processorGbr = Processors.CreateProcessor("GBR");
Console.WriteLine(processorGbr.Process("This is some text."));
// create and use a processor for one-time use
Console.WriteLine(Processors.Process("FRA", "This is some more text."));
Here's a working dotnet fiddle example...
You place all the country-specific processing in each country class. Create a common class (in the Processing class) for all the actual individual methods, so each country processor becomes a list of other common calls, rather than copy the code in each country class.
Note: You'll need to add...
using System.Assembly;
in order for the static method to create an instance of the country class.
A few versions ago, the C# swtich was given full support for pattern matching. So that "multiple countries match" case is easily done. While it still has no fall through ability, one input can match multiple cases with pattern matching. It could maybe make that if-spam a bit clearer.
Npw a switch can usually be replaced with a Collection. You need to be using Delegates and a Dictionary. Process can be replaced with.
public delegate string ProcessDelegate(string text);
Then you could make a Dictionary:
var Processors = new Dictionary<string, ProcessDelegate>(){
{ "USA", EnglishProcessor },
{ "GBR", EnglishProcessor },
{ "DEU", GermanProcessor }
}
I used functionNames to hand in the Delegate. But you could use the Lambda syntax to provide the entire code there. That way you could just hide that whole Collection like you would any other large collection. And the code becomes a simple lookup:
ProcessDelegate currentProcessor = Processors[country];
string processedString = currentProcessor(country);
Those are pretty much the two options. You may want to consider using Enumerations instead of strings for the matching, but that is a minor detail.
I would perhaps (depending on the details of your use-case) go with the Country being a "real" object instead of a string. The keyword is "polymorphism".
So basically it would look like this:
public interface Country {
string Process(string text);
}
Then you can create specialized countries for those that you need. Note: you don't have to create Country object for all countries, you can have LatinlikeCountry, or even GenericCountry. There you can collect what should be done, even re-using others, like:
public class France {
public string Process(string text) {
return new GenericCountry().process(text)
.replace('a', 'b');
}
}
Or similar. Country may be actually Language, I'm not sure about the use-case, but I you get the point.
Also, the method of course should not be Process() it should be the thing that you actually need done. Like Words() or whatever.
You want to delegate to (nod to chain of responsibility) something that knows about its own culture. So use or make a Country or CultureInfo type construct, as mentioned above in other answers.
But in general and fundamentally your problem is you are taking procedural constructs like 'processor' and applying them to OO. OO is about representing real world concepts from a business or problem domain in software. Processor does not translate to anything in the real world apart from software itself. Whenever you have classes like Processor or Manager or Governor, alarm bells should ring.
I was wondering if there was a pattern out there that would help with
this type of process
Chain of reponsibility is the kind of thing you may be looking for but in OOP is somewhat cumbersome...
What about a more functional approach with C#?
using System;
namespace Kata {
class Kata {
static void Main() {
var text = " testing this thing for DEU ";
Console.WriteLine(Process.For("DEU")(text));
text = " testing this thing for USA ";
Console.WriteLine(Process.For("USA")(text));
Console.ReadKey();
}
public static class Process {
public static Func<string, string> For(string country) {
Func<string, string> baseFnc = (string text) => text;
var aggregatedFnc = ApplyToUpper(baseFnc, country);
aggregatedFnc = ApplyTrim(aggregatedFnc, country);
return aggregatedFnc;
}
private static Func<string, string> ApplyToUpper(Func<string, string> currentFnc, string country) {
string toUpper(string text) => currentFnc(text).ToUpper();
Func<string, string> fnc = null;
switch (country) {
case "USA":
case "GBR":
case "DEU":
fnc = toUpper;
break;
default:
fnc = currentFnc;
break;
}
return fnc;
}
private static Func<string, string> ApplyTrim(Func<string, string> currentFnc, string country) {
string trim(string text) => currentFnc(text).Trim();
Func<string, string> fnc = null;
switch (country) {
case "DEU":
fnc = trim;
break;
default:
fnc = currentFnc;
break;
}
return fnc;
}
}
}
}
NOTE:
It does not have to be all static of course. If Process class need state you can use a instanced class or partially applied function ;) .
You can build the Process for each country on startup, store each one in a indexed collection and retrieve them when needed with O(1) cost.
I’m sorry that I long ago coined the term “objects” for this topic because
it gets many people to focus on the lesser idea. The big idea is
messaging.
~ Alan Kay, On Messaging
I would simply implement routines Capitalise, RemovePunctuation etc. as subprocesses that can be messaged with a text and country parameters, and would return a processed text.
Use dictionaries to group countries that fit a specific attribute (if you prefer lists, that would work as well with only a slight performance cost). For example: CapitalisationApplicableCountries and PunctuationRemovalApplicableCountries.
/// Runs like a pipe: passing the text through several stages of subprocesses
public string Process(string country, string text)
{
text = Capitalise(country, text);
text = RemovePunctuation(country, text);
// And so on and so forth...
return text;
}
private string Capitalise(string country, string text)
{
if ( ! CapitalisationApplicableCountries.ContainsKey(country) )
{
/* skip */
return text;
}
/* do the capitalisation */
return capitalisedText;
}
private string RemovePunctuation(string country, string text)
{
if ( ! PunctuationRemovalApplicableCountries.ContainsKey(country) )
{
/* skip */
return text;
}
/* do the punctuation removal */
return punctuationFreeText;
}
private string Replace(string country, string text)
{
// Implement it following the pattern demonstrated earlier.
}
I feel that the information about the countries should be kept in data, not in code. So instead of a CountryInfo class or CapitalisationApplicableCountries dictionary, you could have a database with a record for each country and a field for each processing step, and then the processing could go through the fields for a given country and process accordingly. The maintenance is then mainly in the database, with new code only needed when new steps are needed, and the data can be human readable in the database.
This assumes the steps are independent and don't interfere with each other; if that is not so things are complicated.
What would be the easiest and least labour intensive (from the software POV) for me to be able to get a property (to be read and modified) from an entity generated via the Entity Framework?
Example (and simplified code) below:
// <auto-generated> from Entity Framework
public partial class tblCustomer
{
public int CustomerID { get; set; }
public string Status { get; set; }
}
For instance I would like:
tblCustomer customer = new tblCustomer();
int pCustomerID = customer.GetFieldByName("CustomerID");
pCustomerID = 100;
I've read a lot of answers about Reflection, but also comments that it's heavy processing (may be a bit excessive for my needs).
My example code may seem rather simplistic (so a solution would be rather pointless for that, the real code is based on large tables), but if there was some sort of GetFieldByName function I could reduce my code significantly as I have a lot of repetitious code doing the same stuff (just to different columns).
If I understand your problem correctly, I think you can use the changetracker for this (if the entity is in the context already).
dbContext.Entry(customer).CurrentValues["CustomerID"]
will give you the value of CustomerID for the customer object, provided it is attached to the dbContext instance.
If it is not part of the context, you can use Attach() to attach it first, or use Add(), if it's supposed to be a new record.
If you don't like to use Reflection the only way that i know is using a dictionary in your entities and also you can put all these stuff in a base class and your entities inherit it for example like that:
[Serializable]
public class BaseEntity
{
Dictionary<string, object> _dic;
public BaseEntity()
{
_dic = new Dictionary<string, object>();
}
public object this[string propertyName]
{
get
{
return _dic[propertyName];
}
set
{
_dic[propertyName] = value;
}
}
}
public class tblCustomer : BaseEntity
{
public int CustomerID
{
get
{
return (int)this["CustomerID"];
}
set
{
this["CustomerID"] = value;
}
}
public string Status
{
get
{
return (string)this["Status"];
}
set
{
this["Status"] = value;
}
}
}
tblCustomer customer = new tblCustomer();
int pCustomerID = customer["CustomerID"];
and about performance cost of Reflection you can for first time store your memberInfos in a static field and use it for all instances.
I have a class wherein I want to use Strings with a fixed size.
The reason for the fixed size is that the class "serializes" into a textfile
with values with a fixed length. I want to avoid to write foreach value a guard clause and instead have the class handle this.
So I have round about 30 properties which would look like this
public String CompanyNumber
{
get
{
return m_CompanyNumber.PadLeft(5, ' ');
}
set
{
if (value.Length > 5)
{
throw new StringToLongException("The CompanyNumber may only have 5 characters", "CompanyNumber");
}
m_CompanyNumber = value;
}
}
I would like to have a String that handles this by itself. Currently I have the following:
public class FixedString
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > 5)
{
throw new StringToLongException("The FixedString value may consist of 5 characters", "value");
}
m_FixedString= value;
}
public static implicit operator FixedString(String value)
{
FixedString fsv = new FixedString(value);
return fsv;
}
public override string ToString()
{
return m_FixedString.PadLeft(5,' ');
}
}
The problem I have with this solution is that I can't set the String length at "compile time".
It would be ideal if it would look something like this in the end
public FixedString<5> CompanyNumber { get; set; }
I would go further back and question the design. This solution mashes together two concerns--internal application state and storage format--that should remain separate.
You could decorate each string property with a MaxLengthAttribute and then validate to that, but your code for (de)serializing from your storage format should be completely separate. It could use the same attributes to glean the field lengths for storage (if that happy coincidence holds) but your internal representation shouldn't "know" about the storage details.
Make FixedString take the size as a constructor parameter, but not the value itself
public class FixedString
{
private string value;
private int length;
public FixedString(int length)
{
this.length = length;
}
public string Value
{
get{ return value; }
set
{
if (value.Length > length)
{
throw new StringToLongException("The field may only have " + length + " characters");
}
this.value = value;
}
}
}
Initilise it with your class, and just set the Value when it changes
public class MyClass
{
private FixedString companyNumber = new FixedString(5);
public string CompanyNumber
{
get{ return companyNumber.Value; }
set{ companyNumber.Value = value; }
}
}
You can define an Interface like this:
public interface ILength
{
int Value { get; }
}
Some struct that implements the interface:
public struct LengthOf5 : ILength
{
public int Value { get { return 5; } }
}
public struct LengthOf10 : ILength
{
public int Value { get { return 10; } }
}
And then:
public class FixedString<T> where T : struct, ILength
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > default(T).Value)
{
throw new ArgumentException("The FixedString value may consist of " + default(T).Value + " characters", "value");
}
m_FixedString = value;
}
public static implicit operator FixedString<T>(String value)
{
FixedString<T> fsv = new FixedString<T>(value);
return fsv;
}
public override string ToString()
{
return m_FixedString;
}
}
To be honest I don't know if i like this solution but is the best I can think to solve your problem.
You could put an attribute over your String property and then validate all of them at some time (maybe a button click or something like that).
using System.ComponentModel.DataAnnotations;
public class MyObject
{
[StringLength(5)]
public String CompanyName { get; set; }
}
public void Save(MyObject myObject)
{
List<ValidationResult> results = new List<ValidationResult>();
ValidationContext context = new ValidationContext(myObject, null, null);
bool isValid = Validator.TryValidateObject(myObject, context, results);
if (!isValid)
{
foreach (ValidationResult result in results)
{
// Do something
}
}
}
More about DataAnnotations here.
I think your original idea of creating a string of fixed length is a very valid one, strictly modelling the domain of your system and using the type system to verify it is an idea that I find very appealing. Questions like this seem to come up very often within the F# community.
Unfortunately something like the type definition you suggested (FixedString<5>) is not possible in the context of .NET.
Some of the answers so far have talked about workarounds, alternatives or other ideas, I'd like to instead answer why you can't do what you originally requested in C#.
First of all, lets look at how you could do this in an arbitrary language:
Templates: You could do something like this in C++ using the template system. As Eric Lippert puts it in his article on the differences between generics and templates, "You can think of templates as a fancy-pants search-and-replace mechanism" (https://blogs.msdn.microsoft.com/ericlippert/2009/07/30/whats-the-difference-part-one-generics-are-not-templates/).
.NET generics are, in many ways, far simpler by comparison. Generic types are allow you to parametrise over types but not over values and open types are resolved at runtime whereas templates are an entirely compile time construct.
Dependent Types: A few languages support a feature called dependent types (https://en.wikipedia.org/wiki/Dependent_type). This allows you to define types that depend upon values. Many languages that support this feature are geared toward theorem proving rather than general purpose development.
Idris is perhaps unusual in being a general purpose language under active development (albeit a little known one) which does support this feature (see http://www.idris-lang.org/).
C#
C# does not support either of these features so, unfortunately, you can't solve this problem in a way that can be rigorously verified by the compiler.
I think there are plenty of good suggestions covered here for how you might implement something like this in C# but they all boil down to run-time verification.
We are planning a pretty big application.
-We want to internationalize our application for 30 countries.
-In most countries 1 to 6 different brands are available.
-Each combination of a certain locale like 'de' and brand like 'XXX' might occur multiple times therefore we need another identifier to get something unique:
"locale_brand_siteorigin"
Therefore we have .resx file like:
Configurations.de.burgerking.px10.resx
The bold printed is the unique identifier.
During runtime we create a:
var rm = new ResourceManager("MyNamespace.Configurations.UniqueIdentifier",Assembly.GetExecuting());
Depending on our business logic we can create the above resourceManager.
Finally we will end up having 180+ resx files with all combinations of the unique identifier.
Do you know of a better way to do this kind of branding?
4 years ago someone asked this question, but none answered:
Industry standard for implementing application branding?
UPDATE
I also want to extend my question asking for a solution showing the benefits of using the cultureandregioninfobuilder class to create those many custom cultures.
https://msdn.microsoft.com/en-us/library/system.globalization.cultureandregioninfobuilder(v=vs.110).aspx
I wouldn't recommend using .resx files for such a huge project. When a website is translated in many different languages, usually a lot of people are involved in the copy management, translation etc. These people will not be able to edit the .resx files since they are technically embedded in the application code. This means that your developers will have to constantly update the resources every time there are changes... a real nightmare for everybody.
I recently build a database-driven system for the SumoSoft.Cms. All the strings can be managed through the Admin panel, while in the code you just use:
#CmsMethods.StringContent("ContentSection_Name", "Fallback_Value")
This Helper queries the Database looking for an entity of Type "ContentSection" which is structured more or less like this:
public class ContentSection
{
public string Name { get; set; }
public ICollection<ContentSectionLocalizedString> LocalizedStrings { get; set; }
}
Each LocalizedString contains a reference to a specific Country and a property "Content", so all the Helper does is to choose the one that matches the Current Culture of the Thread.
Expanding on #FrancescoLorenzetti84 answer, one way I've done it in the past to make it easier to maintain is to wrap the database retrieval in a ResourceString class so that you can do something like:
private static readonly ResourceString res = "The value";
and then refer to that in the code. Behind the scene, the ResourceString class does the work. Here is an example of that:
namespace ResString
{
public interface IResourceResolver
{
string Resolve(string key, string defaultValue);
}
public class ResourceString
{
public ResourceString(string value)
{
this.defaultValue = value;
GetOwner();
}
public string Value
{
get
{
if (!resolved)
Resolve();
return value;
}
}
public override string ToString()
{
return Value;
}
public static implicit operator string(ResourceString rhs)
{
return rhs.Value;
}
public static implicit operator ResourceString(string rhs)
{
return new ResourceString(rhs);
}
protected virtual void Resolve()
{
if (Resolver != null)
{
if (key == null)
key = GetKey();
value = Resolver.Resolve(key, defaultValue);
}
else
{
value = defaultValue;
}
resolved = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
protected virtual void GetOwner()
{
StackTrace trace = new StackTrace();
StackFrame frame = null;
int i = 1;
while (i < trace.FrameCount && (owner == null || typeof(ResourceString).IsAssignableFrom(owner)))
{
frame = trace.GetFrame(i);
MethodBase meth = frame.GetMethod();
owner = meth.DeclaringType;
i++;
}
}
protected virtual string GetKey()
{
string result = owner.FullName;
FieldInfo field = owner.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(f =>
typeof(ResourceString).IsAssignableFrom(f.FieldType) && f.GetValue(null) == this
).FirstOrDefault();
if (field != null)
result += "." + field.Name;
return result;
}
public static IResourceResolver Resolver { get; set; }
private string defaultValue;
private string value;
private bool resolved;
private string key;
private Type owner;
}
}
And an example program:
namespace ResString
{
class Program
{
/// <summary>
/// Description for the first resource.
/// </summary>
private static readonly ResourceString firstRes = "First";
/// <summary>
/// Description for the second resource.
/// </summary>
private static readonly ResourceString secondRes = "Second";
/// <summary>
/// Description for the format string.
/// </summary>
private static readonly ResourceString format = "{0} {1}";
static void Main(string[] args)
{
ResourceString.Resolver = new French();
Console.WriteLine(String.Format(format, firstRes, secondRes));
}
private class French : IResourceResolver
{
public string Resolve(string key, string defaultValue)
{
switch (key)
{
case "ResString.Program.firstRes":
return "Premier";
case "ResString.Program.secondRes":
return "Deuxième";
case "ResString.Program.format":
return "{1} {0}";
}
return defaultValue;
}
}
}
}
If you run that, it will output:
Deuxième Premier
Comment out the Resolver assignment and you will get:
First Second
Any where you would use a string in the UI, use a declared ResourceString instead.
Changing the resolver after the string values have been resolved will not alter their value as the values are retrieved only once. You will of course need to write a real resolver that pulls from a database.
What you will then need is a utility program to run through the compiled classes and pull out the ResourceString declarations and put the key and default values into a database or text file so they can be translated. This should also go through the generated help XML files for each assembly and pull the comment for the ResourceString declarations so the translator has some context to work with. The key declarations will also provide context as you can easily group resources by UI class.
Add this to a build script the make sure it is updated regularly.
You can use the same approach with images and the like.
Lets say I have a class ApplicationState which holds the state of an application it has a collection of Globs. Each Glob must have a unique name therefore it should be somehow related to ApplicationState which is holding a list of all Globs. My thoughts were that each Glob should be capable of its own validation so I introduced GlobValidator that checks whether the name is valid by going through the list of ApplicationState Globs. So now I am wondering whether the fact of ApplicationState knowing about Globs which know about GlobValidator that knows about AplicationState will really be painful in the feature and should be changed.
public class GlobValidator
{
private readonly IEnumerable<Glob> _globs;
public GlobValidator(IEnumerable<Glob> globs )
{
_globs = globs;
}
public bool IsValidName(string name)
{
bool isThereGlobWithSameName = _globs.Any(g => g.Name == name);
return !isThereGlobWithSameName;
}
}
public class Glob
{
private readonly GlobValidator _globValidator;
private string _name;
public Glob(string name, GlobValidator globValidator)
{
_globValidator = globValidator;
Name = name;
}
public string Name
{
get { return _name; }
set
{
if (_globValidator.IsValidName(value))
{
_name = value;
}
}
}
}
public class GlobFactory
{
private readonly GlobValidator _globValidator;
public GlobFactory(GlobValidator globValidator)
{
_globValidator = globValidator;
}
public Glob CreateGlob(string name)
{
if (!_globValidator.IsValidName(name))
{
throw new Exception("Invalid Glob Name");
}
return new Glob(name, _globValidator);
}
}
public class ApplicationState
{
public ApplicationState()
{
Globs = new List<Glob>();
}
public List<Glob> Globs { get; set; }
}
The annoyance that I have encountered with thus far is during De-serialization of ApplicationState from XML. As Example
ApplicationState
Globs
[0] Glob.Name = "John"
[1] Glob.Name = "Jeff"
Now given such state when I de-serialize I cannot give Globs the real GlobValidator which has a reference to real ApplicationState without clearing the Globs from application state, otherwise if there is glob with the same name in xml exception will be thrown by GlobValidator. I do not want to clear all the Globs from ApplicationState preparing for the case that xml is faulty in which case I want the previous ApplicationState to be untouched. So now my choice in this approach is to create a temporary reference of GlobValidator which has a reference to a temporary ApplicationState. The price for this is in the case of successful XML serialization I will need to go through and reset the GlobValidator reference on each Glob to reference the real validator, this does not sound like a bad tradeoff to me for having ability of Globs validating themselves.
Am I making a mistake trying to have the Glob being able to validate themselves? Should I be creating some sort of a wrapper around Glob that does the validation using the ApplicationState? Or does this approach sound sane?
P.S. I am using WPF so Globs implement INotifyPropertyChanged and ApplicationState has a list of ObservableCollection of `Glob's