473,414 Members | 1,876 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,414 software developers and data experts.

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<MyRecordto 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.FindRecordById(int id)
{
// return a Record
}
public R FindRecordById(int id)
{
return (R)((IStore)this).FindRecordById(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<MyRecord// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

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

public class MyOtherStore : MyOtherStore<MyOtherRecord>
{
}

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 2739
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>(Store<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<MyRecordto 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.FindRecordById(int id)
{
// return a Record
}
public R FindRecordById(int id)
{
return (R)((IStore)this).FindRecordById(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<MyRecord// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

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

public class MyOtherStore : MyOtherStore<MyOtherRecord>
{
}

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>(Store<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<MyRecordto 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.FindRecordById(int id)
{
// return a Record
}
public R FindRecordById(int id)
{
return (R)((IStore)this).FindRecordById(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<MyRecord// non generic version
{
}

// a subclass of MyStore...

public class MyOtherRecord : MyRecord
{
}

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

public class MyOtherStore : MyOtherStore<MyOtherRecord>
{
}

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.NewRecord()
{
// 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<Criteria>{}

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
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...
231
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...
2
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...
1
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...
23
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...
8
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),...
22
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...
11
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? ...
7
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
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
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,...
0
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...
0
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...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

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.