Check type with boolean property? - c#

I'm very aware of type checking, but have found myself in a unique situation and I'm beginning to question whether I'm within best practices. Hopefully the veteran comments will give me some direction and things worth thinking more deeply about. And, to be honest, it's not that what I have will not work, but as I'm making some other changes I'm wondering what the pitfalls might be and whether I should change tactics. There doesn't seem to be a lot out there (in fact I havent' seen anything as basic type checking takes the majority of the search results).
I have a situation where I'm developing a bill of material interface system. In this system, the following class diagram applies:
This is generically speaking, but the point here is that there are only three concrete types worth concerning. Because it's easy to set property values in the constructors of the objects, I had defined (generically speaking again of course) the IMaterial interface as so:
public interface IMaterial
{
bool IsCommodity { get; }
bool IsAssembly { get; }
bool IsUnclassified { get; }
...
}
Originally, the thought was that the object graph has very little room to change, performance is improved through a preset boolean value, and I don't have to worry about breaking various other principles by type checking concrete types.
So for example, I can do this...
bool hasCommodities = materialCollection.Any(item => item.IsCommodity);
bool hasAssemblies = materialCollection.Any(item => item.IsAssembly);
bool hasDescriptionOnly = materialCollection.Any(item => item.IsUnclassified);
or this...
if (bomMaterial.IsAssembly)
{
symbol = new BomAssemblySymbol();
}
else
{
symbol = new BomItemSymbol();
}
instead of this...
bool hasCommodities = materialCollection.Any(item => item is ClassifiedItem);
bool hasAssemblies = materialCollection.Any(item => item is Assembly);
bool hasDescriptionOnly = materialCollection.Any(item => item is UnclassifiedItem);
or this...
if (bomMaterial is Assembly)
{
symbol = new BomAssemblySymbol();
}
else
{
symbol = new BomItemSymbol();
}
So in my case, the interface's use of properties means less dependency on concrete types in the implementation detail. But then again, it begs the question, what if another type does come along? What's the best answer here? And is there a pattern that maybe I'm overlooking and should be considering for this? And if anyone is wondering why the consuming code cares, it's because with the CAD system, there is a single command the user interacts with that in turn leverages these objects. I can't create separate commands for them just because of the single line of code difference.
Update
Here's a more complete example showing how the CAD-side seems to bottle neck processes. The TryGetMaterialInformation() method prompts the user in the CAD system for specific input. The SymbolUtility.InsertSymbol() method just wraps a common set of user prompts for inserting any symbol and then inserts it.
public override void Execute()
{
IMaterial bomMaterial = null;
bool multipleByReference = false;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
if (!TryGetMaterialInformation(out bomMaterial, out multipleByReference))
{
ed.WriteMessage("\nExiting command.\n");
return;
}
IBlockSymbol symbol;
if (bomMaterial.IsAssembly)
{
symbol = new BomAssemblySymbol();
}
else
{
symbol = new BomItemSymbol();
}
if (multipleByReference)
{
SymbolUtility.InsertMultipleByReferenceSymbol(symbol, bomMaterial);
}
else
{
SymbolUtility.InsertSymbol(symbol, bomMaterial);
}
}
From SymbolUtility
internal static void InsertSymbol(IBlockSymbol symbol, IMaterial material)
{
ICADDocumentDTO document = new CADDocumentDTO();
Editor ed = document.ActiveDocument.Editor;
//Get the insert point
Point3d insertPoint = Point3d.Origin;
if (!CommandUtility.TryGetPoint("Select insert point: ", out insertPoint))
{
ed.WriteMessage("\nExiting command.\n");
return;
}
//Insert the object
using (ISystemDocumentLock documentLock = document.Lock())
{
CreateSymbolDefinition(symbol, document);
symbol.Insert(insertPoint, material, document);
}
}

If you have properties like IsCommodity, IsAssembly, and IsClassified, they should describe some sort of logical property that can be ascribed to an instance. They should not tell the consumer what the concrete type is.
The reason is that a consumer of IMaterial should neither know nor need to know about any concrete type that implements IMaterial.
If those properties actually indicate the concrete types, then all those properties accomplish is type checking, and they will lead to casting objects back to their concrete types, which defeats the purpose of creating an abstraction (interface.)
It looks that way to me since you're considering the properties as a direct alternative to type checking.
The alternative is that instead of the consumer looking at the class properties and deciding what to do or not to with the class, the consumer just tells the class what do to (calling a method) and the implementation of the class itself determines how to carry that out.

Related

How can factory's have access to other factory's products in abstract factory pattern

In this example for the NYPizzaIngredientFactory, they can only make pizza with ThinCrustDough. How can i make a pizza that could use another factory's ingredients like ThickCrustDough from ChicagoPizzaIngredientFactory. I want to try stay away from builder and stick with abstract factory patterns and factory methods.
Your NYPizzaStore would have to use the ChicagoPizzaIngredientFactory if you want it to be able to use ThickCrustDough.
If you think about the practicality of this, however, it probably doesn't make sense to have them ship you the ingredients from Chicago.
In my mind, you have two options:
Have another factory located in NY that can produce thick dough (e.g. NYThickPizzaIngredientFactory). This is because your interface has a single createDough method that takes no arguments so you can't tell it what type of dough to make. It can only make one.
Alter your interface so that the createDough method accepts arguments that can tell the factory what type of dough to create. This is the one I would recommend.
The type of arguments can also be based on the particular factory. For instance:
//TDoughArts tells you what type of arguments the factory needs in order to make dough.
public interface IPizzaIngredientFactory<TDoughArgs> where TDoughArgs : IDoughArgs
{
//....
IDough CreateDough(TDoughArgs doughArgs);
//....
}
public interface IDoughArgs
{
}
public class NYPizzaDoughArgs : IDoughArgs
{
public enum DoughTypes
{
Thin = 0,
Thick = 1
}
public DoughTypes DoughType { get; set; }
}
public class NYPizzaIngredientFactory : IPizzaIngredientFactory<NYPizzaDoughArgs>
{
//....
public IDough CreateDough(NYPizzaDoughArgs doughArgs)
{
//Make the right dough based on args here
if(doughArgs.DoughType == DoughTypes.Thin)
//...
}
//....
}
I whipped this out in a few minutes so check for consistency, but I think you will get the idea.
You don't have to use generics. You can simply stick with the IDoughArgs interface if you don't want more specificity.
Usage:
var factory = new NYPizzaIngredientFactory();
var args = new NYPizzaDoughArgs();
args.DoughType = NYPizzaDoughArgs.DoughTypes.Thick;
var dough = factory.createDough(args);
The first problem I see is this:
public interface IDoughArgs
{
}
public class NYPizzaDoughArgs : IDoughArgs
{
public enum DoughTypes
{
Thin = 0,
Thick = 1
}
public DoughTypes DoughType { get; set; }
}
IDoughArgs has no members. The class that implements it, NYPizzaDoughArgs, has properties which are not implementations of IDoughArgs. That renders the IDoughArgs interface meaningless.
Additionally, look at this class declaration:
public class NYPizzaIngredientFactory : IPizzaIngredientFactory<NYPizzaDoughArgs>
What class is going to "know" the generic argument and know to create this class as opposed to some other generic implementation? It's going to get confusing when you get to that part. You'll need some sort of factory to create your factory.
Then, if you decide that ingredient factories vary by more than just the type of dough, and you need more generic arguments, it's going to get really messy.
And, what happens if, in addition to having options such as thickness that are specific to just one dough type, you need options that are specific to just one thickness? Perhaps thick dough is only an option if you've selected New York or Chicago style (not European) and stuffed crust is only an option if you've selected a thick crust. That's going to get really difficult to describe with interfaces. It sounds more like data.
Here's a stab at another way to implement this:
public enum PizzaStyle
{
NewYork = 1,
Chicago = 2,
Greek = 4
}
public enum CrustType
{
Thick = 1024,
Thin = 2048,
HandTossed = 4096
}
public enum CrustOption
{
Stuffed = 32768
}
public enum PizzaDoughOption
{
NewYorkThin = PizzaStyle.NewYork + CrustType.Thin,
NewYorkHandTossed = PizzaStyle.NewYork + CrustType.HandTossed,
NewYorkThick = PizzaStyle.NewYork + CrustType.Thick,
NewYorkThickStuffed = NewYorkThick + CrustOption.Stuffed,
ChicagoThin = PizzaStyle.Chicago + CrustType.Thin,
ChicagoHandTossed = PizzaStyle.Chicago + CrustType.HandTossed,
ChicagoThick = PizzaStyle.Chicago + CrustType.Thick,
ChicagoThickStuffed = ChicagoThick + CrustOption.Stuffed,
Greek = PizzaStyle.Greek // only comes one way?
}
There are other ways to represent this same data. Even if there were fifty values in the PizzaDoughOption enumeration, it's probably still easier that way, building a definitive, readable list of valid options, as opposed to trying to represent that in code with a bunch of branches. (If you want to unit test that, you'll end up coding every single combination anyway in unit tests.)
And there are several ways you could use this data. You could present just a big list of options. You could allow users to select from the various options and, as you go, determine whether it matches a valid combination. Or they could select any option and you could narrow the list of options according to which include the desired option. (You want a stuffed crust? Ok, that's either New York thick crust or Chicago thick crust.)
Now, if you need a factory to create dough according to type, you could do this:
public interface IDoughFactory
{
Dough GetDough(PizzaDoughOption doughOption);
}
The implementation might look something like this. To be honest I might use a "factory factory" here, but for now since there are only three types I'll keep it simpler.
public class DoughFactory : IDoughFactory
{
// Each of these also implement IDoughFactory
private readonly NewYorkDoughFactory _newYorkDoughFactory;
private readonly ChicagoDoughFactory _chicagoDoughFactory;
private readonly GreekDoughFactory _greekDoughFactory;
public DoughFactory(
NewYorkDoughFactory newYorkDoughFactory,
ChicagoDoughFactory chicagoDoughFactory,
GreekDoughFactory greekDoughFactory)
{
_newYorkDoughFactory = newYorkDoughFactory;
_chicagoDoughFactory = chicagoDoughFactory;
_greekDoughFactory = greekDoughFactory;
}
public Dough GetDough(PizzaDoughOption doughOption)
{
if (MatchesPizzaStyle(doughOption, PizzaStyle.NewYork))
return _newYorkDoughFactory.GetDough(doughOption);
if (MatchesPizzaStyle(doughOption, PizzaStyle.Chicago))
return _chicagoDoughFactory.GetDough(doughOption);
if (MatchesPizzaStyle(doughOption, PizzaStyle.Greek))
return _greekDoughFactory.GetDough(doughOption);
// Throw an exception or return a default dough type. I'd throw the exception.
}
private bool MatchesPizzaStyle(PizzaDoughOption doughOption, PizzaStyle pizzaStyle)
{
return ((int) doughOptions & (int) pizzaStyle) == (int) pizzaStyle;
}
}
Now your more concrete dough factories (New York, Chicago, Greek) all receive the same PizzaDoughOption. If they care whether thin or thick has been selected, they can handle it. If that option doesn't exist they can ignore it. Even if something has gone wrong in an outer class and somehow someone has invoked GreekDoughFactory with the StuffedCrust option, it won't fail. It just ignores it.
What would be the possible point to all of this?
First, the class creating a pizza has no knowledge of the intricacies of creating the right dough type. It just depends on a dough factory, passes a parameter, and gets the right dough. That's simple and testable.
Second, you don't have to call new anywhere. You can employ dependency injection all the way down. That way the class that depends on the abstract IDoughFactory doesn't know anything about what dependencies DoughFactory has.
Likewise, maybe the concrete dough factories have dependencies of their own and they differ significantly from one to the next. As long as those are getting resolved from the container and injected into DoughFactory, that's fine, and DoughFactory won't know anything about their dependencies.
All of the dependencies are wired up in your DI container, but the classes themselves are small, simple, and testable, depending on abstractions and not coupled to implementations of anything.
Someone might look and this and think it's a little more complicated. What's critical is that not only does it keep individual classes decoupled, but it leaves a path forward for future change. The design of your classes, which shouldn't have to change too much, won't closely mirror the details of specific types of pizzas, which can and should change. You don't want to have to re-architect your pizza application because of a new kind of pizza.

C# LSP Constructor Parameters and Guard Clauses

I've been reading about the Liskov Substitution Principle (LSP) and I'm a little confused on how you adhere to it correctly. Especially when interfaces and subclasses are being used.
For example, if I have a base class:
public abstract class AccountBase
{
private string primaryAccountHolder;
public string PrimaryAccountHolder
{
get { return this.primaryAccountHolder; }
set
{
if (value == null) throw ArgumentNullException("value");
this.primaryAccountHolder = value;
}
}
public string SecondaryAccountHolder { get; set; }
protected AccountBase(string primary)
{
if (primary == null) throw new ArgumentNullException("primary");
this.primaryAccountHolder = primary;
}
}
Now let's say I have two accounts that inherit from the base class. One that REQUIRES the SecondaryAccountHolder. Adding a null guard to the sub-class is a violation of LSP, correct? So how would I design my classes in such a way that they don't violate LSP but one of my sub-classes requires a secondary account holder and one does not?
Compound the question with the fact that there could be tons of different types of accounts and they'll need to be generated through a factory or factory that returns a builder or something.
And I have the same question with interfaces. If I have an interface:
public interface IPrintsSomething
{
void PrintSomething(string text);
}
Wouldn't it be a violation of LSP to add a null guard clause for text on any class that implements IPrintsSomething? How do you protect your invariants? That is the correct word right? :p
You should research tell-don't-ask, and command/query separation, you could start here: https://pragprog.com/articles/tell-dont-ask
You should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do.
There's always something you want to do with the properties, well don't ask the object for them tell it to do something with them.
Instead of asking it and making decisions like this:
string holders = account.PrimaryAccountHolder;
if (accountHolder.SecondaryAccountHolder != null)
{
holders += " " + accountHolder.SecondaryAccountHolder;
}
Tell it:
string holders = account.ListAllHoldersAsAString();
Ideally, you'd actually tell it what you actually want to do with that string:
account.MailMergeAllAccountHoldersNames(letterDocument);
Now the logic for dealing with two account holders is in the subclass. Could be one, two or n account holders, the calling code doesn't care or need to know.
As for LSP, well if there's a formally (or informally) documented contract that says the clients must check for null on the second holder from the start then that's fine. It's not nice, but any null-pointer-exceptions will be the client's fault for not using the class correctly. (Note it's not true that adding a boolean property improves upon this, it's just maybe a little more readable, i.e. does anyone check IList.IsReadOnly before writing to it?!).
However, if you started with the double holder account and then added that condition that the second account holder can be null later for the single account, then you changed the contract, and an instance of the single could break existing code. If you're in full control of all places that use accounts, then you're allowed to do that, if that's a public api
you're changing, that's a different matter.
But tell-don't-ask avoids the whole problem in this case.
So how would I design my classes in such a way that they don't violate LSP but one of my sub-classes requires a secondary account holder and one does not?
The way out of this problem is by surfacing this variability to the contract of the base class. It may look like this (unnecessary implementation details left out):
public abstract class AccountBase
{
public string PrimaryAccountHolder
{
get { … }
set { … }
}
public string SecondaryAccountHolder
{
get { … }
set
{
…
if (RequiresSecondaryAccountHolder && value == null) throw …;
…
}
}
public abstract bool RequiresSecondaryAccountHolder { get; }
}
Then you are not violating the LSP, because the user of AccountBase can determine whether they have to or have not to provide the value of SecondaryAcccountHolder.
And I have the same question with interfaces. … Wouldn't it be a violation of LSP to add a null guard clause for text on any class that implements IPrintsSomething?
Make the validation an obvious part of the interface's contract. How? Document, that the implementor must chek the value of text for null.

Bit of a brain teaser: Custom logic strings with C# classes

So, my basic set up is like so: I have items, which are restricted to different classes. These items have effects, which are also restricted to different classes. For example, I might have an item that may only be wielded by elves, while another item might be wielded by everyone, but gives specific bonuses/effects to elves.
Here's a Restriction class:
public class Restriction {
private int _base_id = 0;
private bool _qualify = true;
public Restriction() { }
// ... Base_ID and Qualify getters and setters here
public virtual bool Check(int c) {
if(_qualify) { return c == _base_id; }
else { return c != _base_id; }
}
A child of the Restriction class might be RaceRestriction, which only overrides the constructor:
public RaceRestriction(reference.races r, bool qual) {
Base_ID = (int)r; Qualify = qual;
}
reference.races r is an enum in a reference file. The idea here is that I can extend this "Restriction" syntax to any class that I define in the reference file -- so I can make Restrictions on race, class, stats, whatever I need.
So, this all culminates later, when I define (for example) an item, which has restrictions on who can equip it.
Below is a snippet from the Equipment class, where I define a piece of equipment for later use (hopefully it's readable as is):
public Equipment() {
...
_master_equipment_list[1] = new Equipment {
Name = "Sword",
Description = "It's just a sword for demonstration",
Stats = {
new Attribute {
Stat_Modifier = new KeyValuePair<reference.stats, int>(reference.stats.ATTACK, 5),
Restrictions = {
new RaceRestriction(reference.races.TROLL, false)
}
}
},
Restrictions = {
new ClassRestriction(reference.class.WARRIOR, true)
}
}
So the idea behind this is that using this system, I've defined a sword that can only be used by warriors (base warrior true restriction on the item), and it gives 5 attack to any trolls wielding it.
What I've cornered myself into is that this will only work for either logical AND or logical OR strings of thought. Say my item says "warriors can use this" and it says "elves can use this." Do I really mean "warriors or elves" or do I mean "warrior elves?"
That distinction, I think, is going to be necessary -- so I need to attach some logic to each restriction and make, essentially, I think, sets of restrictions that are tied to one another, that string with other sets of restrictions, etc., but I feel like that will get out of hand very fast.
Is there a better way I can do this?
Rather than defining specific restriction classes, I would design this by defining an interface called IRestrictable to be implemented by the Equipment classes. This interface would contain at least one method called CheckEligibility (or similar) which would return a bool. Your equipment class would then be free to use whatever logic expression it liked to come up with the answer, based on whatever inputs you wanted and whatever information the class had available at the time. You could have several methods on the interface if you need to check restrictions under different circumstances. You would be free to implement specific classes deriving from Equipment for specific types of equipment that had complicated rules.

Help me understand how to use a class in OOP C#

I'm creating an application that basically downloads and uploads files from various types of locations. I asked some advice on here and I was told that I should take an Object Oriented Approach with something like this, but this is my first real usage of OOP so I'm having a hard time understanding how to carry out what I want. Here is what I have so far:
public class FileListClass
{
public string sourcetype;
public string source;
public string destination;
public string destinationtype;
public bool deleteSource;
}
How do I actually enter a file into here in my main method? When I create a new list based on this class, .Add on the list requires an item of 'FileListClass' type - how do I create this?
you can do some thing lik ethis
FileListClass oFileListClass = new FileListClass();
oFileListClass.sourcetype="";
oFileListClass.source="";
oFileListClass.destination="";
oFileListClass.destinationtype="";
oFileListClass.deleteSource=false;
this will create one object, and you can create as many as possible like this with diffrent values.
if you wana keep this in List then create list of type FileListClass like
List<FileListClass > oListFileListClass = new List<FileListClass >();
then add all of your objects in this like
oListFileListClass.Add(oFileListClass);
Short answer:
var yourList = new System.Collections.Generic.List<FileListClass>();
yourList.Add(new FileListClass
{
sourcetype = "...",
source = "...",
...
});
Longer answer:
The above should work, but do take note that your class is not particularly well-designed (IMHO). It's more of a simple data record/container than a class that's "true" to OO principles. This may be just fine, depending on your requirements.
It's uncommon to expose fields directly in C#. Usually, only properties are exposed: public string SourceType { get; set; }
sourcetype and destinationtype are slightly suspect -- this might be a case where subclassing (class inheritance) might be suitable later on. Even without that, and without me knowing what exactly you're going to store in those two fields, have you considered using enums for them instead of plain strings?
In C#, it's common practice to name public members with CamelCase capitalization.
First, it's a bettere approach to define Enums for your constant types, something like
public enum SourceTypes
{
Network = 0,
WAN =1,
}
ecc. ecc.
then modify your FileLystClass as follows
public class FileListClass
{
public SouceTypes sourceType;
...
public DestinationTypes destinationType;
...
}
then, to answer your question.
You have defined a a class(a type) called FileListClass.
To use it, just create as many instance you want, populating the fields of the objects accordingly to your sources
public void CreateFileListList()
{
for (int i = 0; i <100; i++)
{
FileListClass flo = new FileListClass
flo.sourceType = SourceTypes.WAN;
flo.deletesource = true;
[...]
myList.add(flo);
}
}
I would suggest laying out the basic actions that are needed in your program:
DownloadFrom(String loc);
UploadFrom(String loc);
Then you can build lower levels of your app:
DownloadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
UploadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
At this point you can already have a feeling of the structure of your program, you can in fact create classes around your different actions:
class Connect {
HTTPConnect();
FTPConnect();
}
class Download : Connect{
DownloadFrom(String loc);
}
class Upload : Connect{
UploadFrom(String loc);
}
As you can see this is a first approach to OOP. There are many advantages to use a structure of Objects around your program but It would be too hard of an explanation. Try reading Google about it: Advantages of OOP.

Best practice for giving back extra information from a Validate function

I have a class Employee. I want to be able to Validate() it before I save it to make sure all the fields have been populated with valid values.
The user of the class may call Validate() before they call Save() or they may call Save() directly and Save() will then call Validate() and probably throw an Exception if validation fails.
Now, my (main) question is this;
If my Validate() function returns a simple bool then how do I tell the user of the class what is wrong, i.e. "Email not filled in", "ID not unique" etc. For the purposes of this I just want the error strings to pass to the human user, but the principle is the same if I wanted a list of error codes (except that makes the use of a bitmap more logical).
I could use an Out paramater in my Validate function but I understand this is frowned upon.
Rather than returning a bool, I could return a string array from my function and just test if it was empty (meaning no errors) - but that seems messy and not right.
I could create a Struct just to return from this method, including a bool and a string array with error messages, but just seems clunky.
I could return a bitmap of error codes instead of a bool and look it up, but that seems rather excessive.
I could create a public property "ValidationErrors" on the object which would hold the errors. However, that would rely on me calling Validate() before reading it or explicitly calling Validate from the Property() which is a bit wasteful.
My specific program is in C# but this looks like a fairly generic "best practice" question and one I am sure I should know the answer to. Any advice gratefully received.
I could create a Struct just to return from this method, including a bool and a string array with error messages, but just seems clunky.
Why does it seem clunky? Creating an appropriate type to encapsulate the information is perfect. I wouldn't necessarily use a string to encode such information, though. An enum may be better suited.
An alternative would be to subclass the return type and provide an extra child class for every case – if this is appropriate. If more than one failures may be signalled, an array is fine. But I would encapsulate this in an own type as well.
The general pattern could look like this:
class ValidationInfo {
public bool Valid { get; private set; }
public IEnumerable<Failure> Failures { get; private set; }
}
I would probably go for the bitmap-option. Simply
[Flags]
public enum ValidationError {
None = 0,
SomeError = 1,
OtherError = 2,
ThirdError = 4
}
...and in the calling code, simply:
ValidationError errCode = employee.Validate();
if(errCode != ValidationError.None) {
// Do something
}
Seems nice and compact to me.
I would follow the pattern of the TryParse methods and use a method with this signature:
public bool TryValidate(out IEnumerable<string> errors) { ... }
Another option is to pull the validation code out of the object into its own class, possibly building on the Specification pattern.
public class EmployeeValidator
{
public bool IsSatisfiedBy(Employee candidate)
{
//validate and populate Errors
}
public IEnumerable<string> Errors { get; private set; }
}
I have found it a good approach to simply have a method (or a property, since C# has nice support for that) which returns all validation error messages in some kind of sensible, easy to use format, such as a list of strings.
This way you can also keep your validate method returning bools.
Sounds like you need a generic class:
public sealed class ValidationResult<T>
{
private readonly bool _valid; // could do an enum {Invalid, Warning, Valid}
private readonly T _result;
private readonly List<ValidationMessage> _messages;
public ValidationResult(T result) { _valid = true; _result = result; _messages = /* empty list */; }
public static ValidationResult<T> Error(IEnumerable<ValidationMessage> messages)
{
_valid = false;
_result = default(T);
_messages = messages.ToList();
}
public bool IsValid { get { return _valid; } }
public T Result { get { if(!_valid) throw new InvalidOperationException(); return _result; } }
public IEnumerable<ValidationMessage> Messages { get { return _messages; } } // or ReadOnlyCollection<ValidationMessage> might be better return type
// desirable things: implicit conversion from T
// an overload for the Error factory method that takes params ValidationMessage[]
// whatever other goodies you want
// DataContract, Serializable attributes to make this go over the wire
}
You could take a look at Rockford Lhotka's CSLA which has extensive business rule/validation tracking forr business objects in it.
www.lhotka.net
I agree with Chris W. I asked the same questions, before reading Rocky`s Expert C# Business Objects.
He has a brilliant way of handling business validation rules. The validation is done after each property is set. Whenever a rule is broken, the object`s state become InValid.
Your business class can implement the IDataError interface. Binding your UI controls to your business object properties will then notify your ErrorProvider control of any broken rules on your object.
I would really recommend you take the time and look at the validation section.
We are using spring validation together with an Windows Forms error provider.
So our validation function returns a dictionary with a control id and an error message (for every validation error). The error provider shows the error message in a pop up field near the control which caused the error.
I used some other validation schemes in the past - but this one works really well.

Categories

Resources