473,728 Members | 1,650 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Casting Generic Classes - Possible Solution

I have an object which could be compared to a DataTable/List which I am
trying to genericify.

I've spent about a day so far in refactoring and in the process gone
through some hoops and hit some dead ends.

I'm posting this to get some feedback on wether I'm going in the right
direction, and at the same time hopefully save others from going
through the process.

The starting point. I have a "Store" class which provides ways to get
hold of "Record"s.. .

public class Record {
}
public class Store
{
Record FindRecordById( int id)
{
// return a Record
}

public string StoreName { get {return "Store"}};
}
So my first attempt to use generics was this...

public class Record
{
}

public class Store<Rwhere R : Record
{
R FindRecordById( int id)
{
// return an R
}

public string StoreName { get {return "Store"}};
}
I wanted to pass Store<Record>s around and use them as a base class for
activities however I found that is not possible due to casting issues.
e.g. I can't cast Store<MyRecordt o Store<Record>.
The best explanation is that you can't cast a List<MyClassto a
List<objectas is it will allow the caster to add objects to a MyClass
based lists!

So I tried adding an interface into the structure:

public interface IStore
{
string StoreName {get;}
}

public class Store<R: IStore where R : Record
{
public string StoreName { get {return "Store"}};
}

I can now pass the IStore around without the casting problem.

Then I came to the issue that I wanted to add methods to the interface
based on the generic R class.
I can't make it a generic interface as this will bring me back to the
original problem.
So I came up with this structure:

public interface IStore
{
Record FindRecordById( int id);
}

public class Store<R: IStore where R : Record
{
Record IStore.FindReco rdById(int id)
{
// return a Record
}
public R FindRecordById( int id)
{
return (R)((IStore)thi s).FindRecordBy Id(id);
}
}

Thus, if its cast as an IStore I have access to the non generic method,
and if its cast to the generic class I get the generic one.
They don't interfere with each other as they are visible at different
times.

Just to complete the story, I also wanted to be able to have non
generic class wrappers to my store classes but still be able to
subclass in a generic way. So I came up with this:

public class MyRecord : Record
{
}

public class MyStore<R: Store<Rwhere R : MyRecord, new()
{
}

public class MyStore : MyStore<MyRecor d// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

public class MyOtherStore<R: MyStore<Rwhere R : MyOtherRecord,
new()
{
}

public class MyOtherStore : MyOtherStore<My OtherRecord>
{
}

I've just thought. With this structure I will not be able to cast a
MyOtherStore to a MyStore. This could be an issue. I'll sleep on that
one.

All this seems to be working (compiling anyhow). I still have a lot of
code to refactor.

I'm also thinking, the whole point of the exercise was to reduce
potential errors with tighter compile time type checking, but it seems
I'm ending up doing more run-time casting thus defeating the point! I
think it would still help in reducing errors in business logic which
uses these classes, which might mean its worth while.

Any comments would be appreciated.

Tigger

Jul 29 '06 #1
3 2771
Try the following; when passing around the store, instead of declaring
the param as Store<Record>, you need to use (e.g. as a method)

public void SomeMethod<T>(S tore<Tstore) where T : Record {
// something
}

You can then call via

Store<MyRecordx = new Store<MyRecord> (); // where MyRecord : Record
SomeMethod(x);

This works as saying "accept a store of anything that are Record
items". Inside SomeMethod, the compiler knows that any T : Record, so
you have access to any available members defined on the base-class (but
not the subclasses).

Marc

Tigger wrote:
I have an object which could be compared to a DataTable/List which I am
trying to genericify.

I've spent about a day so far in refactoring and in the process gone
through some hoops and hit some dead ends.

I'm posting this to get some feedback on wether I'm going in the right
direction, and at the same time hopefully save others from going
through the process.

The starting point. I have a "Store" class which provides ways to get
hold of "Record"s.. .

public class Record {
}
public class Store
{
Record FindRecordById( int id)
{
// return a Record
}

public string StoreName { get {return "Store"}};
}
So my first attempt to use generics was this...

public class Record
{
}

public class Store<Rwhere R : Record
{
R FindRecordById( int id)
{
// return an R
}

public string StoreName { get {return "Store"}};
}
I wanted to pass Store<Record>s around and use them as a base class for
activities however I found that is not possible due to casting issues.
e.g. I can't cast Store<MyRecordt o Store<Record>.
The best explanation is that you can't cast a List<MyClassto a
List<objectas is it will allow the caster to add objects to a MyClass
based lists!

So I tried adding an interface into the structure:

public interface IStore
{
string StoreName {get;}
}

public class Store<R: IStore where R : Record
{
public string StoreName { get {return "Store"}};
}

I can now pass the IStore around without the casting problem.

Then I came to the issue that I wanted to add methods to the interface
based on the generic R class.
I can't make it a generic interface as this will bring me back to the
original problem.
So I came up with this structure:

public interface IStore
{
Record FindRecordById( int id);
}

public class Store<R: IStore where R : Record
{
Record IStore.FindReco rdById(int id)
{
// return a Record
}
public R FindRecordById( int id)
{
return (R)((IStore)thi s).FindRecordBy Id(id);
}
}

Thus, if its cast as an IStore I have access to the non generic method,
and if its cast to the generic class I get the generic one.
They don't interfere with each other as they are visible at different
times.

Just to complete the story, I also wanted to be able to have non
generic class wrappers to my store classes but still be able to
subclass in a generic way. So I came up with this:

public class MyRecord : Record
{
}

public class MyStore<R: Store<Rwhere R : MyRecord, new()
{
}

public class MyStore : MyStore<MyRecor d// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

public class MyOtherStore<R: MyStore<Rwhere R : MyOtherRecord,
new()
{
}

public class MyOtherStore : MyOtherStore<My OtherRecord>
{
}

I've just thought. With this structure I will not be able to cast a
MyOtherStore to a MyStore. This could be an issue. I'll sleep on that
one.

All this seems to be working (compiling anyhow). I still have a lot of
code to refactor.

I'm also thinking, the whole point of the exercise was to reduce
potential errors with tighter compile time type checking, but it seems
I'm ending up doing more run-time casting thus defeating the point! I
think it would still help in reducing errors in business logic which
uses these classes, which might mean its worth while.

Any comments would be appreciated.

Tigger
Jul 29 '06 #2
I didn't realise you could do that, thanks!

I've decided to use interfaces as the way I pass Store references
around. It leaves me with the open option to use generics or not when I
implement the concrete classes.

I had a quick play with using generic methods and I quickly came across
my down casting issue. Once I've refactored to interfaces I''ll be able
to look into it better.

Thanks

Tigger

Marc Gravell wrote:
Try the following; when passing around the store, instead of declaring
the param as Store<Record>, you need to use (e.g. as a method)

public void SomeMethod<T>(S tore<Tstore) where T : Record {
// something
}

You can then call via

Store<MyRecordx = new Store<MyRecord> (); // where MyRecord : Record
SomeMethod(x);

This works as saying "accept a store of anything that are Record
items". Inside SomeMethod, the compiler knows that any T : Record, so
you have access to any available members defined on the base-class (but
not the subclasses).

Marc

Tigger wrote:
I have an object which could be compared to a DataTable/List which I am
trying to genericify.

I've spent about a day so far in refactoring and in the process gone
through some hoops and hit some dead ends.

I'm posting this to get some feedback on wether I'm going in the right
direction, and at the same time hopefully save others from going
through the process.

The starting point. I have a "Store" class which provides ways to get
hold of "Record"s.. .

public class Record {
}
public class Store
{
Record FindRecordById( int id)
{
// return a Record
}

public string StoreName { get {return "Store"}};
}
So my first attempt to use generics was this...

public class Record
{
}

public class Store<Rwhere R : Record
{
R FindRecordById( int id)
{
// return an R
}

public string StoreName { get {return "Store"}};
}
I wanted to pass Store<Record>s around and use them as a base class for
activities however I found that is not possible due to casting issues.
e.g. I can't cast Store<MyRecordt o Store<Record>.
The best explanation is that you can't cast a List<MyClassto a
List<objectas is it will allow the caster to add objects to a MyClass
based lists!

So I tried adding an interface into the structure:

public interface IStore
{
string StoreName {get;}
}

public class Store<R: IStore where R : Record
{
public string StoreName { get {return "Store"}};
}

I can now pass the IStore around without the casting problem.

Then I came to the issue that I wanted to add methods to the interface
based on the generic R class.
I can't make it a generic interface as this will bring me back to the
original problem.
So I came up with this structure:

public interface IStore
{
Record FindRecordById( int id);
}

public class Store<R: IStore where R : Record
{
Record IStore.FindReco rdById(int id)
{
// return a Record
}
public R FindRecordById( int id)
{
return (R)((IStore)thi s).FindRecordBy Id(id);
}
}

Thus, if its cast as an IStore I have access to the non generic method,
and if its cast to the generic class I get the generic one.
They don't interfere with each other as they are visible at different
times.

Just to complete the story, I also wanted to be able to have non
generic class wrappers to my store classes but still be able to
subclass in a generic way. So I came up with this:

public class MyRecord : Record
{
}

public class MyStore<R: Store<Rwhere R : MyRecord, new()
{
}

public class MyStore : MyStore<MyRecor d// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

public class MyOtherStore<R: MyStore<Rwhere R : MyOtherRecord,
new()
{
}

public class MyOtherStore : MyOtherStore<My OtherRecord>
{
}

I've just thought. With this structure I will not be able to cast a
MyOtherStore to a MyStore. This could be an issue. I'll sleep on that
one.

All this seems to be working (compiling anyhow). I still have a lot of
code to refactor.

I'm also thinking, the whole point of the exercise was to reduce
potential errors with tighter compile time type checking, but it seems
I'm ending up doing more run-time casting thus defeating the point! I
think it would still help in reducing errors in business logic which
uses these classes, which might mean its worth while.

Any comments would be appreciated.

Tigger
Jul 31 '06 #3
Ok,

I eventually got all my code refactored to the new "generic" solution.

In summary I would say that the few benefits are outweighed by the
complexity it has introduced, and I wouldn't do it again. I might even
reverse out the generic code but I will keep the core interface
concept.

In the final solution a common template was created which I can easily
incorporate into my code generator.

The main Store...

public interface IStore // interface to use when referencing Stores
{
// as this is how all external code accesses stores the external code
// has no advantage from the fact that generics is used :-(
// all public methods/properties from the generic class have to be
duplicated here

Record NewRecord();
...
}
public sealed class Store : Store<Record>
{
// this class is needed so I can easily instantiate an instance from
// a string that represents the class to use. (new() does not seem to
help in this regard)
// sealed to stop subclassing (the generic class should be
subclassed)
}
public class Store<R: IStore where R : Record, new()
{
Record IStore.NewRecor d()
{
// I have to create an interface version of a method converting the
R into its base type
// it is only visible to the interface
return this.NewRecord( );
}

public R NewRecord()
{
// actual implementation using generics
// this ends up being effectively protected as the interface
version
// is our public view of the class
return new R(); // can I do this? if not call it pseudo code
}
...
}

// example sub class...

public partial interface ICriteriaStore : IStore
{
// partial to allow code generation
// includes base store so NewRecord() is also possible!

Criteria NewCriteria();
...
}
public sealed class CriteriaStore : CriteriaStore<C riteria>{}

public partial class CriteriaStore<R : Store<R>, ICriteriaStore where
R : Criteria, new()
{
Criteria ICriteriaStore. NewCriteria()
{
// note, no casting needed...we're actually using the generics!
return NewRecord();
}
...
}

Conclusion: Don't go there!

Aug 3 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1501
by: Leon Mergen | last post by:
Hello, Ok, I'm having a problem when trying to make the classes I make a bit more generic. Consider this: I have one class, ClassA. This defines some interface methods, and ClassB inherits from it, and adds some of its own variables. Now, I'm making a library, which accepts ClassA. Now the problem is, this library also creates a lot of threads. I want
231
23174
by: Brian Blais | last post by:
Hello, I saw on a couple of recent posts people saying that casting the return value of malloc is bad, like: d=(double *) malloc(50*sizeof(double)); why is this bad? I had always thought (perhaps mistakenly) that the purpose of a void pointer was to cast into a legitimate date type. Is this wrong? Why, and what is considered to be correct form?
2
9186
by: Lars-Erik Aabech | last post by:
Hi! I've got a small challenge with my class library. I've got an abstract base class with some protected fields. It has two derived classes, and it should be possible to cast these classes to each other. The variables to be persisted are the ones from the base class. It is possible to cast upwards, but I'm not allowed to cast downwards. The only solution I found was to create explicit casting operators on each of the derived classes....
1
8351
by: Mark McDonald | last post by:
This question kind of follows on from Mike Spass’ posting 10/11/2004; I don’t understand why you can’t declare an implicit operator to convert a base class to a derived class. The text books say “neither the source nor the target types of a conversion can be a base type of the other, since a conversion would then already exist”. But this is not really true, whilst automatic (implicit) conversions do occur from the derived...
23
3519
by: Ren Nordby | last post by:
Hi there, Is there anyone that knows how to do the following? I have a class A and a class B, that 100% inherits from class A (this means that I don't have other code in class B, than the Inherit statement).
8
2131
by: Michael | last post by:
Hi, I think my problem deals with class casting and inheritance. I want to deal with various Audio Formats, reading into memory for modification, working with it (done by different classes), and writing the result to disk afterwards. Therefore I have created some classes, e.g. WaveFileIO and AiffFileIO and MP3FileIO and AuFileIO for the In/Out operations.
22
13116
by: Adam Clauss | last post by:
OK, I have class A defined as follows: class A { A(Queue<B> queue) { ... } } Now, I then have a subclass of both classes A and B. The subclass of A (SubA), more specifically is passed a Queue<SubB>.
11
32439
by: Frederic Rentsch | last post by:
Hi all, If I derive a class from another one because I need a few extra features, is there a way to promote the base class to the derived one without having to make copies of all attributes? class Derived (Base): def __init__ (self, base_object): # ( copy all attributes ) ...
7
2213
by: Ajeet | last post by:
hi I am having some difficulty in casting using generics. These are the classes. public interface IProvider<PROF> where PROF : IProviderProfile { //Some properties/methods }
0
8753
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9411
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9188
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9122
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8113
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing, and deploymentwithout human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6704
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupr who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4522
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
2643
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2159
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.