Some kind of wrapper class

S

stocki

Hi,

There is a class "cSQLServer" and a class "cOracle". Both have same
methods and properties. A third class (presenter) instanciates both of
them an shows the retrieved data in two separate listviews. So far, so
good.

Now I was asked to implement an additional cExcel class in order to
compare it against the Oracle data. I came to the conclusion to write
a wrapper class in which I load either "cSQLServer" or "cExcel"
depending on the users choice.

Something like:
cWrapper wrapper = new cWrapper() ;
cOracle oracle = new cOracle();
private void buttonSQLServer_Click(object sender, EventArgs e)
{
wrapper = new cSQLServer() ;
}

private void buttonExcel_Click(object sender, EventArgs e)
{
wrapper = new cExcel() ;
}

private void ShowVals()
{
this.lvwLoad .... = wrapper.GetData();
this.lvwComp .... = oracle.GetData();

}

Is this feasable and does it make sense? Can somebody point me in the
right direction how to implement something like that? Any hint is
highly appriciated!

Thank's in advance!

Andreas
 
J

Jon Skeet [C# MVP]

Is this feasable and does it make sense? Can somebody point me in the
right direction how to implement something like that? Any hint is
highly appriciated!

My first hint would be to start using class names which follow
the .NET naming convention.

That said, you should create an interface that both the Oracle and SQL
Server classes implement, with the GetData() method and anything else
in common which you need to call. Then just use the interface,
basically.

Jon
 
S

stocki

That said, you should create an interface that both the Oracle and SQL
Server classes implement, with the GetData() method and anything else
in common which you need to call. Then just use the interface,
basically.

Jon

Hi Jon,

Thank you for your quick response. This was the way I was actually
thinking of in the first run. The problem is though and I have
forgotten to mention it in my previous post, that I need some kind of
communication between e.g. cSQLServer and the presenter. For example
is the user in a position to limit the number of columns retrieved, or
he changes the order of columns. That makes it necessary to pass this
information back to the cSQLServer.

Working with an interface, as far as I know, works only in one
direction. Please correct me if I am wrong. This draw my attention on
the wrapper stuff

Cheers

Andreas
 
J

Jon Skeet [C# MVP]

stocki said:
Thank you for your quick response. This was the way I was actually
thinking of in the first run. The problem is though and I have
forgotten to mention it in my previous post, that I need some kind of
communication between e.g. cSQLServer and the presenter. For example
is the user in a position to limit the number of columns retrieved, or
he changes the order of columns. That makes it necessary to pass this
information back to the cSQLServer.

Working with an interface, as far as I know, works only in one
direction. Please correct me if I am wrong. This draw my attention on
the wrapper stuff

Just make them properties in the interface, or parameters in the method
call.

If you really need it to be bidirectional, you could either make the
presenter implement an interface as well and pass that into the
cSQLServer constructor, or you could use events in the interface
implemented by your data sources.
 
S

stocki

Hi John,

digested your answer for quite some hours last night. Unfortunatelly I
came to the conclusion that I will run into some issues regarding the
instances of the several classes. Let me give you an example. As you
know the user can choose between Excel- and SQLServer comparison. So
in the form you will find the following piece of code:

// An instance of the presenter class using the interface. The
following properties and methods startting with "I" are from the
interface-class
IPresenter presenter = new cPresenter() ;
presenter.IDBServer = "server" ;
presenter.IInstanz = "instance" ;
presenter.IDatenbank = "database" ;

// Event to be sent out by the presenter when additional data is
needed
presenter.GetHeadersValsLoadEvent += new EventHandler
( OnGetHeadersValsLoad ) ;

private void btnSQLServer_Click(object sender, EventArgs e)
{
// Server and database credentials
cSQLServer sqlserver = new cSQLServer( presenter ) ;
sqlserver.DBServer() ;
sqlserver.Instanz() ;
sqlserver.Datenbank() ;

// Server and database credentials
cOracle oracle = new cOracle( presenter ) ;
oracle.DBServer() ;
oracle.Instanz() ;
oracle.Datenbank() ;

// Details from SQL Server to Presenter
presenter.ITitelLoad = sqlserver.Titel ;
presenter.IFormatsLoad = sqlserver.Formats ;
presenter.IHeaderValsLoad = sqlserver.GetHeadersVals() ;

// Details from Oracle to Presenter
presenter.ITitelLoad = oracle.Titel ;
presenter.IFormatsLoad = oracle.Formats ;
presenter.IHeaderValsLoad = oracle.GetHeadersVals() ;

// Populate form and show details
presenter.IPrepAndShowView() ;

At that stage the user see all the details, which is fine. Now he
presses a button in the presenter form, to load the details again
(changed column order, less columns etc.) This button sends an event
to the form where the user can choose between Excel and SQLServer
data:

private void OnGetHeadersValsLoad( object sender, EventArgs e )
{
// Now we need to pass the details coming from the presenter to the
current SQLServer class ...
.... = presenter.ISQLItems
}

The problem is that I am not able to access the current SQLSever class
from "OnGetHeadersValsLoad", because it is instantiated in the buttons
click event.

One solution, a not very optimal though, is to destroy the reference
to cSQLServer class in the buttons click event and rebuild it in the
"OnGetHeadersValsLoad" event. It works but the major drawback is, that
you need some kind of indicator, whether cExcel or cSQLServer needs to
be instantiated.

Is there no way to create two wrapper classes, or interface classes,
in which I pass either cSQLServer or cExcel the in the buttons click
event ? This would avoid the indicator issue.

Thanks for all your help!

Cheers

Andreas
 
J

Jon Skeet [C# MVP]

stocki said:
digested your answer for quite some hours last night. Unfortunatelly I
came to the conclusion that I will run into some issues regarding the
instances of the several classes. Let me give you an example. As you
know the user can choose between Excel- and SQLServer comparison. So
in the form you will find the following piece of code:

It's not at all clear to me why the btnSQLServer_Click method is even
*mentioning* cOracle.

The problem is that I am not able to access the current SQLSever class
from "OnGetHeadersValsLoad", because it is instantiated in the buttons
click event.

So make it an instance variable that you hold on to. That's the normal
way of retaining state.
One solution, a not very optimal though, is to destroy the reference
to cSQLServer class in the buttons click event and rebuild it in the
"OnGetHeadersValsLoad" event. It works but the major drawback is, that
you need some kind of indicator, whether cExcel or cSQLServer needs to
be instantiated.

Is there no way to create two wrapper classes, or interface classes,
in which I pass either cSQLServer or cExcel the in the buttons click
event ? This would avoid the indicator issue.

I'm afraid I'm somewhat lost at this point as to what you're trying to
do...
 
S

stocki

Hi Jon,
I'm afraid I'm somewhat lost at this point as to what you're trying to
do...

sorry, that was of course not my intention! I have no Visio installed
on this machine, so can't draw a schema at the present moment.

To make a long story short. I would like to do the following:
Create a loader and a comparer class

Loader loader = new Loader() ;
Comparer comparer = new Comparer();

Next step is to pass the users choice into the classes.
On Excel choice (btnExcel_Click):

loader = new cExcel() ;
comparer = new cOracle() ;

// Details from Excel to Presenter
presenter.ITitelLoad = loader.Titel ;
presenter.IFormatsLoad = loader.Formats ;
presenter.IHeaderValsLoad = loader.GetHeadersVals() ;

// Details from Oracle to Presenter
presenter.ITitelComp = comparer.Titel ;
presenter.IFormatsComp = comparer.Formats ;
presenter.IHeaderValsComp = comparer.GetHeadersVals() ;

presenter.PrepAndShowView

On SQLServer choice (btnSQLServer_Click):

loader = new cSQLServer() ;
comparer = new cOracle() ;

// Details from Excel to Presenter
presenter.ITitelLoad = loader.Titel ;
presenter.IFormatsLoad = loader.Formats ;
presenter.IHeaderValsLoad = loader.GetHeadersVals() ;

// Details from Oracle to Presenter
presenter.ITitelComp = comparer.Titel ;
presenter.IFormatsComp = comparer.Formats ;
presenter.IHeaderValsComp = comparer.GetHeadersVals() ;

presenter.PrepAndShowView

First advantage of this solution: As loader and comparer are
instantiated outside the two click events they are valid throughout
the module.
Second advantage: Simplification of the code as the button clicks
routines. The next couple of lines will show all the code of the form
where the user has the choice between the Excel button and the SQL
Server button:

Loader loader = new Loader() ;
Comparer comparer = new Comparer();

private void btnSQLServer_Click(..)
{
loader = new cSQLServer() ;
comparer = new cOracle() ;

GetDataToPresenter() ;
}

private void btnExcel_Click(..)
{
loader = new cExcel() ;
comparer = new cOracle() ;

GetDataToPresenter() ;
}

private void GetDataToPresenter()
{
// Details from Loader to Presenter to be shown in left listview
presenter.ITitelLoad = loader.Titel ;
presenter.IFormatsLoad = loader.Formats ;
presenter.IHeaderValsLoad = loader.GetHeadersVals() ;

// Details from Comparer to Presenter to be shown in right listview
presenter.ITitelComp = comparer.Titel ;
presenter.IFormatsComp = comparer.Formats ;
presenter.IHeaderValsComp = comparer.GetHeadersVals() ;

presenter.PrepAndShowView
}

The two events initiated will be only one liners:
private void OnGetHeadersValsLoad( object sender, EventArgs e )
{
presenter.IHeaderValsLoad =
loader.GetHeadersVals( newColumns ) ; // newColumns is an array
of new column names
}

private void OnGetHeadersValsComp( object sender, EventArgs e )
{
presenter.IHeaderValsComp =
comparer.GetHeadersVals( newColumns ) ; // newColumns is an
array of new column names
}

How need the loader and the comparer class have to look like? Please
keep in mind, that cSQLServer, cOracle and cExcel already have all the
same layout.

Sorry to be a pain!

Cheers

Andreas
 
J

Jon Skeet [C# MVP]

sorry, that was of course not my intention! I have no Visio installed
on this machine, so can't draw a schema at the present moment.

To make a long story short. I would like to do the following:
Create a loader and a comparer class

Loader loader = new Loader() ;
Comparer comparer = new Comparer();

Next step is to pass the users choice into the classes.
On Excel choice (btnExcel_Click):

loader = new cExcel() ;
comparer = new cOracle() ;

// Details from Excel to Presenter
presenter.ITitelLoad = loader.Titel ;
presenter.IFormatsLoad = loader.Formats ;
presenter.IHeaderValsLoad = loader.GetHeadersVals() ;

// Details from Oracle to Presenter
presenter.ITitelComp = comparer.Titel ;
presenter.IFormatsComp = comparer.Formats ;
presenter.IHeaderValsComp = comparer.GetHeadersVals() ;

presenter.PrepAndShowView

On SQLServer choice (btnSQLServer_Click):

loader = new cSQLServer() ;
comparer = new cOracle() ;

// Details from Excel to Presenter
presenter.ITitelLoad = loader.Titel ;
presenter.IFormatsLoad = loader.Formats ;
presenter.IHeaderValsLoad = loader.GetHeadersVals() ;

// Details from Oracle to Presenter
presenter.ITitelComp = comparer.Titel ;
presenter.IFormatsComp = comparer.Formats ;
presenter.IHeaderValsComp = comparer.GetHeadersVals() ;

presenter.PrepAndShowView

So both the loader and the comparer have the same members in both
cases?

Sounds like you need a single interface, and then just two properties
on the Presenter: "Comparer" and "Loader". Your code above then
becomes:

// Excel clicked
presenter.Loader = new cExcel() ;
presenter.Comparer = new cOracle() ;
presenter.PrepAndShowView();

// SQL Server clicked
presenter.Loader = new cSqlServer() ;
presenter.Comparer = new cOracle() ;
presenter.PrepAndShowView();
First advantage of this solution: As loader and comparer are
instantiated outside the two click events they are valid throughout
the module.

Without understanding a lot more about the solution, it's hard to know
whether that's necessarily valid. I don't know about the lifetime of
the various instances, for example.
Second advantage: Simplification of the code as the button clicks
routines.

The above has simplified it quite a lot, I reckon :)

How need the loader and the comparer class have to look like? Please
keep in mind, that cSQLServer, cOracle and cExcel already have all the
same layout.

In my solution outlined above, you don't need extra classes - just an
extra interface, along the lines of:

interface ILoaderComparer
{
Header[] GetHeaderVals();
string Title { get; }
string[] Formats { get; }
}

(I'm completely guessing at the return values here, by the way.)

Make cExcel, cOracle and cSqlServer all implement the interface, and
it sounds like you'll be away.

Jon
 
S

stocki

Hi Jon,

I totally agree that your solution is even better!!!

Just allow me one last question please and this stupid german chap is
gone ;-)

presenter.Loader = new cExcel() ;
presenter.Loader = new cSqlServer() ;

The last piece which is missing is the definition of "Loader" in the
presenter. Here I am completly lost. Would you mind to shed some
light on that please?

I would like to thank you to share your knowledge with me! I have
really learned a lot in the last couple of days!

Cheers

Andreas
 
J

Jon Skeet [C# MVP]

stocki said:
I totally agree that your solution is even better!!!

Just allow me one last question please and this stupid german chap is
gone ;-)

presenter.Loader = new cExcel() ;
presenter.Loader = new cSqlServer() ;

The last piece which is missing is the definition of "Loader" in the
presenter. Here I am completly lost. Would you mind to shed some
light on that please?

It would be a settable property of type IComparerLoader (or whatever
you call the interface). The interface would need to encapsulate
everything that the presenter needs in order to get data from the
loader.
I would like to thank you to share your knowledge with me! I have
really learned a lot in the last couple of days!

My pleasure.
 
S

stocki

Hi Jon,

this breaks the wall! Now I have somthing to do on the weekend. Keep
fingers crossed, that the weather is not too good!

Thank you for all your help and have a nice one!

Cheers

Andreas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top