Wrox Programmer Forums
Go Back   Wrox Programmer Forums > .NET > Other .NET > General .NET
|
General .NET For general discussion of MICROSOFT .NET topics that don't fall within any of the other .NET forum subcategories or .NET language forums.  If your question is specific to a language (C# or Visual Basic) or type of application (Windows Forms or ASP.Net) try an applicable forum category. ** PLEASE BE SPECIFIC WITH YOUR QUESTION ** When posting here, provide details regarding the Microsoft .NET language you are using and/or what type of application (Windows/Web Forms, etc) you are working in, if applicable to the question. This will help others answer the question without having to ask.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the General .NET section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old December 28th, 2006, 09:29 PM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 596
Thanks: 1
Thanked 3 Times in 3 Posts
Default n-tier interface problem

Hi All,
I am constructing an application and I am using interfaces for my Object Layer classes to be used in Data Access and Logic layers.

My question is regarding the use of interfaces in this n-tier design.

For example , If I have a interface called IHouse and it has various properties like Width, Height, or whatever.
In addition to these singular properites I wish to have a collection of custom types. So a house might have a collection of Rooms.
But I want a Room to be an object on its own.
So in my Object Layer will have an iterface for a Room called IRoom.

So this is my problem.
How do I enforce that the classes derived from the IHome have a collection of Rooms.
If I put a property of say List<IRoom> in my IHome interface i am forced to impliment this list in my Logic Layer, but it is of type IRoom, so none of the new methods that are applied to the Derived Room class are available in the derived Home class because it only contains a definition for IRoom not Room.

I would be interested in any comments on how I should approach this.

Many thanks
Rod

======================================
They say, best men are molded out of faults,
And, for the most, become much more the better
For being a little bad.
======================================
__________________
======================================
"They say, best men are molded out of faults,
And, for the most, become much more the better
For being a little bad."
--Shakespeare
======================================
 
Old December 29th, 2006, 06:03 AM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

Hi Rod,

I am not sure if the solution below gives you exactly what you need, but it's worth a try. There may be other alternatives as well so you may need to play around with it.

To make this work, you need to make your IHouse interface generic as well, have it expect a type that somehow implements IRoom and expose a list of that type, like this:
Code:
internal interface IHouse<T> where T : IRoom
{
  List<T> Rooms { get;}
}
This interface enforces a list called Rooms of type T. Type T is then constrained by a where clause that enforces that T implements IRoom.

Next up is the actual House class. Instead of just implementing the IHouse interface, you specify the type of Room that is used by the interface, like this:
Code:
class YourHouse : IHouse<LargeRoom>
{
}
This creates a YourHouse class that will use the LargeRoom class as the generic type for Rooms. So, the List<T> from the interface (originally List<IRoom> in your solution) can look like this:
Code:
public List<LargeRoom> Rooms
{
  get { ..... }
}
With this code, the Rooms list is now strongly typed for LargeRoom objects, so you can access LargeRoom specific properties.

Obviously, you can now create other House classes that implement different kind of rooms with the accompanying Room type:
Code:
class MyStudentHouse : IHouse<SmallRoom>
{

  ...

  public List<SmallRoom> Rooms
  {
    get { ..... }
  }
}
Does this help? All the generics make this code look a little odd, but I think it does what you want....

Cheers,

Imar
---------------------------------------
Imar Spaanjaars
http://Imar.Spaanjaars.Com
Everyone is unique, except for me.
Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004
Want to be my colleague? Then check out this post.
 
Old January 1st, 2007, 08:28 PM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 596
Thanks: 1
Thanked 3 Times in 3 Posts
Default

Hi Imar,
Thanks for your help, your solution looks like what I need, I will definately give it a shot.

I've never used a where clause in a class definition, this is very interesting.
 
Quote:
quote:This interface enforces a list called Rooms of type T. Type T is then constrained by a where clause that enforces that T implements IRoom.


Many thanks again,
Rod

======================================
They say, best men are molded out of faults,
And, for the most, become much more the better
For being a little bad.
======================================
 
Old January 2nd, 2007, 05:22 AM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

You're welcome.

Generics are really powerful, especially in combination with type constraints. If you want to know more about generics, I can really recommend Professional .NET 2.0 Generics
(http://www.wrox.com/WileyCDA/WroxTit...764559885.html) by Tod Golding.

I learned a lot about generics from this book.....

Cheers,

Imar
---------------------------------------
Imar Spaanjaars
Everyone is unique, except for me.
 
Old January 3rd, 2007, 03:08 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 596
Thanks: 1
Thanked 3 Times in 3 Posts
Default

Hi Again Imar,

I keep running in to the same headache and I think I have not seperated my layers very well.

Would you mind having a look at the sample layers below.
I would really like some overall guidance as to whether or not I am heading in the right direction, no need to debug my code, just a comment or two would be much appreciated.

The metaphor is now a company with people (not houses and rooms), my actual application is far more complicated, but this is the problem.

The problem is that I am trying to seprate the DAL,BOL,BLL and GUI layers whilst using a provider model for the DAL, is this a good idea at all?(ie BOL/BLL)

Now when I try to call the GetMessage method it is expecting an interface and will not accept the derived Company object.
If I use the derived object as a parameter in the interface I am no longer seperating the layers.

So the following code in the GUI layer fails to compile.
Code:
BLL.Company c = new BLL.Company();
c.CompanyName = "CoreApps";            
MessageBox.Show(c.GetMessage(c));
<==Errors
Error    1    The best overloaded method match for 'DAL.CompanyProvider.GetMessage(BOL.ICompany<BOL.IPerson>)' has some invalid arguments
Error    2    Argument '1': cannot convert from 'BLL.Company' to 'BOL.ICompany<BOL.IPerson>'    
==>
BOL:
Code:
public interface ICompany<T> where T:IPerson
    {
        string CompanyName { get;set;}
        List<T> People { get;}
        string GetMessage(BOL.ICompany<BOL.IPerson> company);
    }
public interface IPerson
    {
        string FirstName { get; set;  }

        string GetMessage(BOL.IPerson person);
    }

BLL:

Code:
public class Company : DAL.CompanyProvider, BOL.ICompany<Person>
    {
        public Company() { }
        private string companyName;
        public string CompanyName
        {
            get { return companyName; }
            set { companyName = value; }
        }

        private List<Person> people = new List<Person>();
        public List<Person> People{get{return people;}}

        public override string GetMessage(BOL.ICompany<BOL.IPerson> company)
        {
            return DAL.CompanyProvider.Instance.GetMessage(company);
        }
    }
public class Person : DAL.PersonProvider, BOL.IPerson
    {
        public Person() { }
        private string firstName;
        public string FirstName { get { return firstName; } set { firstName = value; } }
        public override string GetMessage(BOL.IPerson person)
        {
            return DAL.PersonProvider.Instance.GetMessage(person);
        }
    }

DAL:
Code:
public abstract class CompanyProvider
    {
        static private CompanyProvider _instance = null;
        /// <summary>
        /// Returns an instance of the provider type specified in the config file
        /// </summary>
        static public CompanyProvider Instance
        {
            get
            {
                if (_instance == null)
                    _instance = (CompanyProvider)Activator.CreateInstance(
                       Type.GetType(ConfigurationSettings.AppSettings["CompanyProvider"].ToString()));
                return _instance;
            }
        }
        public abstract string GetMessage(BOL.ICompany<BOL.IPerson> iCompany);

    }
    public abstract class PersonProvider
    {
        static private PersonProvider _instance = null;
        /// <summary>
        /// Returns an instance of the provider type specified in the config file
        /// </summary>
        static public PersonProvider Instance
        {
            get
            {
                if (_instance == null)
                    _instance = (PersonProvider)Activator.CreateInstance(
                       Type.GetType(ConfigurationSettings.AppSettings["PersonProvider"].ToString()));
                return _instance;
            }
        }
        public abstract string GetMessage(BOL.IPerson person);

    }
and the provider in the DAL
Code:
public class RS232_Company:CompanyProvider
    {
        public override string GetMessage(BOL.ICompany<BOL.IPerson> company)
        {
            return company.CompanyName + "_RS232";
        } 
    }
    public class RS232_Person : PersonProvider
    {
        public override string GetMessage(BOL.IPerson person)
        {
            return person.FirstName + "_RS232";
        }
    }


======================================
They say, best men are molded out of faults,
And, for the most, become much more the better
For being a little bad.
======================================
 
Old January 3rd, 2007, 03:21 AM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

Hi Rod,

I can take a look at this, but probably not before tonight (it's morning here now).

Is it possible to send me a complete VS solution for this? Maybe as a simple console app or class library or whatever you have right now? Makes it easier for me to take a look at it. Please remove as much as possible irrelevant classes etc....

You can send me an e-mail through my profile page, I'll respond and then you have my e-mail address.

Cheers,

Imar
---------------------------------------
Imar Spaanjaars
http://Imar.Spaanjaars.Com
Everyone is unique, except for me.
Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004
Want to be my colleague? Then check out this post.
 
Old January 3rd, 2007, 04:37 PM
Imar's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 17,089
Thanks: 80
Thanked 1,576 Times in 1,552 Posts
Default

Hi Rod,

Bad news; I haven't been able to find a solution. I have been able to get the code to compile by changing a few classes and methods. For example, I changed CompanyProvider to CompanyProvider<T> and I changed Company to:

public class Company : DAL.CompanyProvider<BOL.ICompany<BOL.IPerson>>, BOL.ICompany<Person>

Pretty messy as you can see. It uses nested reflection....

However, I ended up with methods like this:

public string GetMessage(ICompany<Person> iCompany)
{
  return DAL.CompanyProvider<ICompany<Person>>.Instance.Get Message(iCompany);
}

The Person class in the end worked (but I think it already did), but I get run-time errors in the Instance property for the company when this is called:

_instance = (CompanyProvider<T>) Activator.CreateInstance(
   Type.GetType(ConfigurationSettings.AppSettings["CompanyProvider"].ToString()));

This fails because WS_Company cannot be casted to CompanyProvider<T>

This may have to do with how you instantiate generic types with the Activator. There's an article on MSDN that suggests this works a little bit different, but I am not sure if it applies to your situation. http://msdn2.microsoft.com/en-us/library/b8ytshk6.aspx

I think the main reason I can't solve this because I don't really know what you want. I can see what the code does, and what it's supposed to, but I don't know your design decisions, and the things you may be willing to change. For example, why does GetMessage get a reference back to itself:

MessageBox.Show(c.GetMessage(c));

There are other things that may be changed without affecting your original intent that makes it easier to create something like this. However, explaining or building something like this over e-mail is extremely difficult. It would be so much easier if I were sitting next to you with some fresh coffee to think this through... ;)

The answer may be in self referencing types, but I don't know exactly how. In the CSLA .NET 2 Framework by Rockford Lhotka some interesting generics are used, like this:

public class MyList : BusinessListBase<MyList, myChild>

Here, the BusinessListBase class is created with the same type as the type that is defined. This makes for strongly typed properties of type MyList, defined in the base class BusinessListBase. Not sure if, and how this helps, but it may push you in the right direction.

Anyway, it was a fun exercise. I'd be happy to help more if you want, or send the stuff I tried (it's a bit messy now, but it may give you some ideas), but I am afraid that at this point there isn't much for me to do right now....

Cheers,

Imar
---------------------------------------
Imar Spaanjaars
http://Imar.Spaanjaars.Com
Everyone is unique, except for me.
Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004
Want to be my colleague? Then check out this post.





Similar Threads
Thread Thread Starter Forum Replies Last Post
Difference between 3 tier and N-Tier architecture Manoj Bisht ASP.NET 2.0 Professional 2 May 9th, 2008 08:42 AM
Problem With RSA Interface Floetic Java GUI 1 March 25th, 2008 06:14 AM
Problem With Implementing an Interface brettk_1 General .NET 1 February 28th, 2007 11:47 AM
QueryInterface for interface failed problem Birendra ASP.NET 1.x and 2.0 Application Design 1 December 16th, 2005 02:49 PM
Interface IPrincipal Problem nightsun BOOK: ASP.NET Website Programming Problem-Design-Solution 1 December 1st, 2003 06:44 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.