tags:

views:

69

answers:

4

i know whats is happening and why its throwing an error (it does not find GetBrokenRules method because its List) but the reason i posted this question here is to ask for a better design, can anybody guide me here please?

i am working on Facilities class (List..../Building/Floor)

error:

Error 3 'System.Collections.Generic.List' does not contain a definition for 'GetBrokenRules' and no extension method 'GetBrokenRules' accepting a first argument of type 'System.Collections.Generic.List' could be found (are you missing a using directive or an assembly reference?)

error on >>> else if (Campus.GetBrokenRules().Count > 0)

is there any better way to desing my GetBrokenRules() ?

ICampus, IBuilding, IFloor consists of the following

public interface ICampus
    {
        List<BrokenBusinessRule> GetBrokenRules(); 
        int Id { get; }
        string Name { get; }
    }

public interface IFacilities 
{
    List<BrokenBusinessRule> GetBrokenRules();
    List<ICampus> Campus { get; }
    List<IBuilding> Building { get; }
    List<IFloor> Floor { get; }  
}


public class Facilities : IFacilities 
    {
        private List<ICampus> _campus;
        private List<IBuilding> _building;
        private List<IFloor> _floor;  

        public List<ICampus> Campus
        {
            get { return _campus; }
        } 

        public List<IBuilding> Building
        {
            get { return _building; }
        }

        public List<IFloor> Floor
        {
            get { return _floor; }
        } 

        public Facilities(List<ICampus> campus, List<IBuilding> building, List<IFloor> floor)
        {
            _campus = campus;
            _building = building;
            _floor = floor; 
        } 

        public  List<BrokenBusinessRule> GetBrokenRules()
        {
            List<BrokenBusinessRule> brokenRules = new List<BrokenBusinessRule>(); 

           if (Campus == null)
                brokenRules.Add(new BrokenBusinessRule("Facility Campus", "Must have at least one Campus"));
            else if (Campus.GetBrokenRules().Count > 0)
            {
                AddToBrokenRulesList(brokenRules, Campus.GetBrokenRules());
            }

            if (Building == null)
                brokenRules.Add(new BrokenBusinessRule("Facility Building", "Must have at least one Building"));
            else if (Building.GetBrokenRules().Count > 0)
            {
                AddToBrokenRulesList(brokenRules, Building.GetBrokenRules());
            }

            if (Floor == null)
                brokenRules.Add(new BrokenBusinessRule("Facility Floor", "Must have at least one Floor"));
            else if (Floor.GetBrokenRules().Count > 0)
            {
                AddToBrokenRulesList(brokenRules, Floor.GetBrokenRules());
            }       
    }
} 
A: 

I would do the null checks in the constructor and take IEnumerables as argument instead of IList. You can call ToList() on the IEnumerables which has the side benefit of throwing an exception if it's null.

I'd create an IFacility interface with a GetBrokenRules method that returns and IEnumerable

public interface IFacility
{
    IEnumerable<BrokenRules> GetBrokenRules();
}

public static class Utils
{
    public static IEnumerable<BrokenRules> GetRules(this IEnumerable<IFacility> facilities)
    {
        return facilities.SelectMany(x => x.GetBrokenRules());
    }
}

Then have building, floor, campus, etc implement the IFacility interface.

Rodrick Chapman
thanks for that, but my question is more related with GetBrokenRules() method.
Abu Hamzah
Ah, I misinterpreted the question. I didn't realize these were business rules. I thought they were rules such as 'No Smoking within 20 feet' or 'No boys allowed in the girl's building after 10pm'
Rodrick Chapman
A: 

Where are your definitions for ICampus, IBuilding and IFloor? Those seem to be integral to IFacilities. Also, you're calling GetBrokenRules() on a List of objects, rather than on the objects themselves.

I'm going to assume that ICampus, IBuilding and IFloor are defined properly and that, for now, the only problem is that you're calling the method on the list. You'll need to enumerate across the List and call that method on each item. Something like:

Campus.ForEach(c => AddToBrokenRulesList(brokenRules, c.GetBrokenRules()));

(You may need the nVentive Umbrella extensions for .ForEach, I don't remember. But there are other ways to enumerate over a List so that's not critical.)

David
@David: ICampus... has two properties (id, name), the reason calling on a list of Objects is ICampus and IBuilding as a seperate objects..make sense?
Abu Hamzah
@teki: So ICampus (and I'm assuming IBuilding and IFloor) doesn't define GetBrokenRules()? Then you definitely won't be able to call that method on that object. What "broken rules" are you trying to get out of those objects and how are you planning on getting them?
David
how to do i check: else if (Campus.GetBrokenRules().Count > 0)? if i use Campus.ForEach
Abu Hamzah
Should this be more hierarchical? That is, rather than three separate lists of objects, wouldn't it make more sense for each IFacilities object to have a list of ICampus objects, each of which has a list of IBuilding objects, each of which has a list of IFloor objects? It seems to me that for each one to exist, its parents all the way up the chain must also exist, no? Then you'll be able to take a more object-oriented approach to getting the broken rules, since each one can return the list of broken rules it gets from its children. (Though you'll need to define those methods.)
David
@David, i have just udpate my question regards to ICampus,IBuilding,IFloor and it does have GetBrokenRules() in it.
Abu Hamzah
@teki: You may not need to make that check. If GetBrokenRules() returns a properly instantiated empty List and AddToBrokenRulesList() is smart enough to handle that (if it's just doing an AddRange(), I believe that's smart enough) then this will also reduce your calls to GetBrokenRules(), which is a slight improvement in performance and maintainability.
David
@David, unit testing and so far it seems to be going well and i will back shortly. -thanks man.
Abu Hamzah
A: 

GetBrokenRules() does not take any arguments, and it's not an extension method, so it has no idea what list it's supposed to process. More difficult than that, all the lists you want to process are defined as lists of different interface types, so there's no commonality there.

One way to handle this would be to define a new interface that defines the common processing for IBuilding, ICampus, and IFloor, and have each of those interfaces inherit from this new interface (call it IFacility). You could then define GetBrokenRules to take an argument of List, and pass it a List. GetBrokenRules would be able to call methods defined in IFacility, which might be sufficient to get passed your current problem.

However, you'll have to pass the list as an argument, rather than they way you're doing it now (Campus.GetBrokenRules()). You could use this syntax if you can get an extension method to work, but that can be tricky when defining extension methods on generic collections. I'd advise against that for now.

Cylon Cat
+1  A: 
public  List<BrokenBusinessRule> GetBrokenRules()
{
    var brokenRules = new List<BrokenBusinessRule>(); 

   // null is not possible because Campus is supplied in the constructor
   if (!Campus.Any())
        brokenRules.Add(new BrokenBusinessRule("Facility Campus", "Must have at least one Campus"));
   else
   {
       foreach(var campus in  Campus)
       {
           brokenRules.AddRange(campus.GetBrokenRules());
       }
   }

   if (!Building,Any())
        brokenRules.Add(new BrokenBusinessRule("Facility Building", "Must have at least one Building"));
    else
    {
        foreach(var building in Building)
        {
            brokenRules.AddRange(building.GetBrokenRules());
        }
    }

    if (!Floor.Any())
        brokenRules.Add(new BrokenBusinessRule("Facility Floor", "Must have at least one Floor"));
    else
    {
        foreach (var floor in Floor)
        {
            brokenRules.AddRange(floor.GetBrokenRules());
        }        
    }
    return brokenRules;     
}

As far as a redesign, I would first get rid of the ICampus, IBuilding, and IFloor interfaces and program against the classes. I would create an interface that declares the GetBrokenRules behavior and have the business classes implement that. Beyond that, it seems to me that a Campus has Buildings and a Building has Floors so I would design it that way instead of collecting these classes into a Facilities class.

Jamie Ide
@Jamie, thanks for the input, the reason I have loosely classes is that, I have two different scenarios like 1) Facilities which consists of campus/bld/floor 2) Point of Entry uses Campus/Building and I have created two interface 1) IFacilities and 2) IPointOfEntry ... do you still think I should get rid of ICampus, IBuilding, IFloor ?
Abu Hamzah
If you only have one business (not service) class that implements an interface then I would get rid of it because it adds no value. By the way, as noblethrasher pointed out, you should check for null collections in the constructor. If you don't then my comment in the code is wrong.
Jamie Ide
+1 thank you .......
Abu Hamzah