Problems with Generic Collection class.

B

BombDrop

I'm working on a system that has 4 different types of client they
have mostly the same attributes so I decided to create an interface
IClient for them to implement and then just add the differing
attributes as needed to each client class.



Now I get the Client information from a DB and Load them into a Generic
dictionary



The class looks like so



class Class1<T> : Dictionary<int, T> where T:IClient

{



private IndemnityScheme scheme;



public Class1(IndemnityScheme scheme)

{



this.scheme = scheme;





}



public int Load()

{



// "procIndemnityClientSelect";



DataBaseAccess dba = new DataBaseAccess(this.scheme);

SqlDataReader reader =
dba.LoadData("procPrsymClientSelect");

SmartDataReader smartReader = new SmartDataReader(reader);





while (smartReader.Read()) {



AceClient newClient = new AceClient(this.scheme);



newClient.Clientshort = smartReader.GetString("Client
Short Name");

newClient.Clientname = smartReader.GetString("Client
Name");

newClient.Clientref = smartReader.GetInt32("client
ref");

newClient.AddressLine1 = smartReader.GetString("Address
Line 1");

newClient.AddressLine2 = smartReader.GetString("Address
Line 2");

newClient.AddressLine3 = smartReader.GetString("Address
Line 3");

newClient.AddressLine4 = smartReader.GetString("Address
Line 4");

newClient.AddressLine5 = smartReader.GetString("Address
Line 5");

newClient.AddressLine6 = smartReader.GetString("Address
Line 6");

newClient.Telephone = smartReader.GetString("Telephone
No");

newClient.PostCode = smartReader.GetString("post
code");

newClient.Contact = smartReader.GetString("Contact");

// newClient.Handler = smartReader.GetString("Handler");

newClient.Joindate = smartReader.GetString("Join
Date");

newClient.Leavingdate = smartReader.GetString("leaving
Date");

newClient.Salutation =
smartReader.GetString("salutation");

newClient.Email = smartReader.GetString("Email");

newClient.Comments = smartReader.GetString("comments");

base.Add(newClient.Clientref, newClient);





}

smartReader.Close();

smartReader = null;

dba = null;

return base.Count;







}





}



I call the class in my program like so



AceClient c = new AceClient(IndemnityScheme.ACE);

Class1<AceClient> cl = new
Class1<AceClient>(IndemnityScheme.ACE);

cl.Load();



foreach (AceClient ac in cl.Values) {

System.Diagnostics.Debug.WriteLine(ac.Clientshort);



}



Nothing fancy just want to loop throught the collection but on trying
to complie I get an error.





This is the line of code that errors



base.Add(newClient.Clientref, newClient);





Error 24 The best overloaded method match for
'System.Collections.Generic.Dictionary<int,T>.Add(int, T)' has some
invalid arguments



Error 25 Argument '2': cannot convert from 'Prsym.AceClient'
to 'T'



Can anyone tell me what I am doing wrong??
 
L

Larry Lard

BombDrop said:
I'm working on a system that has 4 different types of client they
have mostly the same attributes so I decided to create an interface
IClient for them to implement and then just add the differing
attributes as needed to each client class.

Sounds OK.
Now I get the Client information from a DB and Load them into a Generic
dictionary

The class looks like so

class Class1<T> : Dictionary<int, T> where T:IClient

OK said:
public int Load()
{ [...]
while (smartReader.Read()) {

AceClient newClient = new AceClient(this.scheme);

newClient.Clientshort = smartReader.GetString("Client
Short Name"); [...]
base.Add(newClient.Clientref, newClient);

I call the class in my program like so
AceClient c = new AceClient(IndemnityScheme.ACE);

Class1<AceClient> cl = new
Class1<AceClient>(IndemnityScheme.ACE);

cl.Load(); [...]

Nothing fancy just want to loop throught the collection but on trying
to complie I get an error.

So at run time *in this case*, T will be AceClient; but the compiler
isn't to know that.
This is the line of code that errors
base.Add(newClient.Clientref, newClient);
Error 25 Argument '2': cannot convert from 'Prsym.AceClient'
to 'T'
Can anyone tell me what I am doing wrong??

Since the compiler wants *compile time* type safety, it doesn't matter
that you do actually have T as an AceClient in your particular case.

The solution:
- give all IClient implementors a parameterless constructor. Move the
code in the scheme-accepting ctor to the 'set' part of a property for
the scheme.
- add the 'new' constraint in the declaration of Class1 thus:

class Class1<T> : Dictionary<int, T> where T:IClient, new()
// "When you use the new() constraint with other constraints, it must be
specified last"

- in the Load method, create a new T (rather than a new AceClient) and
set its scheme.

Note that (unfortunately) you can't have a constraint that says 'type T
must have a ctor that accepts a scheme'; you can only require T to have
a parameterless ctor. Which is why you'll have to move the
scheme-setting code.
 
J

Jon Skeet [C# MVP]

BombDrop said:
I'm working on a system that has 4 different types of client they
have mostly the same attributes so I decided to create an interface
IClient for them to implement and then just add the differing
attributes as needed to each client class.

Now I get the Client information from a DB and Load them into a Generic
dictionary

Can anyone tell me what I am doing wrong??

Yes - you're trying to add an AceClient to a dictionary which may not
be of type Dictionary<int,AceClient>.

I suspect you actually just want it to be a Dictionary<int,IClient> or
Dictionary<int,AceClient> instead of keeping it generic, given that
what you're actually adding is always an AceClient.

Jon
 

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