base class cast problem

M

mp

my first attempt to use a base class and subType (if that's the correct
terminology)
defined in Investment.cs:
class Investment
class Stock : Investment
class StockListCollection : List<Stock > { }

definted in view
(defined in Iview.cs interface which view implements)
StockListCollection StockWatchChoiceList { get; set; }

in presenter i'm trying to serialize a StockListCollection from the view
the serialize code takes an argument of List<Investment>
so since StockListCollection is a List<Stock >
and Stock is a Investment
I thought that would work...either i can't 'pass through' from base class to
subclass like that
or something else is wrong in my code or definitions

the signature for the serializing code
public static class XMLInvestmentStore
{
public static void StoreInvestmentChoices ( List<Investment>
InvestmentChoices, string fileName )
{...}

i get the following errors:

first i tried this line
XMLInvestmentStore.StoreInvestmentChoices (
this._mView.StockWatchChoiceList, stockWatchFilename );

and got this error
//Argument '1': cannot convert from
'Investments.Model.StockListCollection' to
'System.Collections.Generic.List<Investments.Model.Investment>'

so i thought i needed a specific cast...so i tried this:
XMLInvestmentStore.StoreInvestmentChoices (
(List<Investment>)this._mView.StockWatchChoiceList, stockWatchFilename );
there i *think* i'm casting a StockListCollection to a List<Investment>???
it's base class???

so then i thought maybe i have to cast stock to investment so i tried
XMLInvestmentStore.StoreInvestmentChoices (
(List<(Investment)Stock>)this._mView.StockWatchChoiceList,
stockWatchFilename );
but apparently you can't "cast inside of another cast"

also tried
XMLInvestmentStore.StoreInvestmentChoices (
(List<Stock>)this._mView.StockWatchChoiceList, stockWatchFilename )
but i get this error
Argument '1': cannot convert from
'System.Collections.Generic.List<Investments.Model.Stock>' to
'System.Collections.Generic.List<Investments.Model.Investment>'

but a Stock Is an Investment so i don't know why I can't make that cast?

at least the error msgs keep changing...so it keeps things interesting...:)
anyone feel like helping shortcut my trial and error?

thanks
mark
 
A

Arne Vajhøj

my first attempt to use a base class and subType (if that's the correct
terminology)
defined in Investment.cs:
class Investment
class Stock : Investment
class StockListCollection : List<Stock> { }

definted in view
(defined in Iview.cs interface which view implements)
StockListCollection StockWatchChoiceList { get; set; }

in presenter i'm trying to serialize a StockListCollection from the view
the serialize code takes an argument of List<Investment>
so since StockListCollection is a List<Stock>
and Stock is a Investment
I thought that would work...either i can't 'pass through' from base class to
subclass like that
or something else is wrong in my code or definitions

X sub class of Y does not mean that List<X> is assignable
to List<Y>.

For good reasons. You can add a Z which is also a sub class
of Y to a List<Y>.

You may look at the new C#/.NET 4.0 where you can restrict
usage to allow something similar to this for interfaces.

Google "C# 4.0 covariance". But it will not work in your
case, because it is only for interfaces and IList does
not use the feature either.

I am pretty sure that you want a List<Investment>.

Arne
 
J

Jeff Johnson

Argument '1': cannot convert from
'System.Collections.Generic.List<Investments.Model.Stock>' to
'System.Collections.Generic.List<Investments.Model.Investment>'

but a Stock Is an Investment so i don't know why I can't make that cast?

I JUST happened to read a nice analogy for this a couple of hours ago, so
let me share the link. (It's a Java tutorial, but the concepts are the
same.)

http://download.oracle.com/javase/tutorial/java/generics/subtyping.html

Read the part about "cages" in the second half.
 
A

Arne Vajhøj

I JUST happened to read a nice analogy for this a couple of hours ago, so
let me share the link. (It's a Java tutorial, but the concepts are the
same.)

http://download.oracle.com/javase/tutorial/java/generics/subtyping.html

Read the part about "cages" in the second half.

ArrayList<Investment> lst = new ArrayList<Stock>();

will not compile in Java, but:

ArrayList<? extends Investment> lst = new ArrayList<Stock>();

actually compiles in Java.

(in this particular form it is rather useless, but it can
have its usage)

Arne
 
J

Jeff Johnson

ArrayList<Investment> lst = new ArrayList<Stock>();

will not compile in Java, but:

ArrayList<? extends Investment> lst = new ArrayList<Stock>();

actually compiles in Java.

(in this particular form it is rather useless, but it can
have its usage)

Right, and that is mentioned. (Basically, you can READ from the collection
but not change it.)
 
M

mp

Arne Vajhøj said:
X sub class of Y does not mean that List<X> is assignable
to List<Y>.

For good reasons. You can add a Z which is also a sub class
of Y to a List<Y>.

You may look at the new C#/.NET 4.0 where you can restrict
usage to allow something similar to this for interfaces.

Google "C# 4.0 covariance". But it will not work in your
case, because it is only for interfaces and IList does
not use the feature either.

I am pretty sure that you want a List<Investment>.

Arne

i tried the following and got this error:
{"The type Investments.Model.Stock was not expected.
Use the XmlInclude or SoapInclude attribute to specify types that are not
known statically."}

public static void StoreInvestmentList ( List<Investment> objectsList,
string fileName )
{
XmlSerializer serializer = null;
try
{
// Create our XML file to hold the serialized data.
using (FileStream fStream = new FileStream ( fileName,
FileMode.Create ))
{
try
{
serializer = new XmlSerializer ( typeof (
List<Investment> ) );
serializer.Serialize ( fStream, objectsList );
}
catch (Exception ex)
{
Debug.Print ( "Unable to Store objects in list...Problem
with XmlSerializer " );
Debug.Print ( "objectsList name {0}", objectsList.ToString
( ) );

Debug.Print ( ex.Message );
throw;
}
}
}
catch (Exception ex)
{
Debug.Print ( "Unable to StoreList of objects...Problem with
FileStream <" + fileName + ">" );
Debug.Print ( ex.Message );
throw;
}
Debug.Print ( "Objects stored in " + fileName );
}
}

*** calling code ***
private void btnGetData_Click(object sender, EventArgs e)
{
List< Investment > testlst = new List<Investment > ( );
for (int i = 0; i < 5; i++)
{ testlst.Add ( new Stock ( "Test " + i.ToString
( ),"Tick"+i.ToString() ) ); }
XMLStoreList.StoreInvestmentList ( testlst ,"TestListStore.xml");
}


*** typedefs ***
[Serializable ( )]
public class Investment {
public Investment()
{ }
public Investment(string name)
{
_name = name;
}
....}
[Serializable ( )]
public class Stock : Investment
{private string _ticker;
public Stock ( ) : base ( ) { }//<<<serialize requires parameterless
ctor
public Stock ( string name, string ticker )
: base ( name )
{
_ticker = ticker;
}
public string Ticker { get { return _ticker; } set { _ticker =
value; } }
}
 
A

Arne Vajhøj

i tried the following and got this error:
{"The type Investments.Model.Stock was not expected.
Use the XmlInclude or SoapInclude attribute to specify types that are not
known statically."}

Hm.

XmLSerializer can be a bit tricky with stuff like this.
*** typedefs ***
[Serializable ( )]

If you insert:

[XmlInclude(typeof(Stick)), XmlInclude(typeof(AnotherInvestment))]

here then it should work but that is not a nice solution.

I can not come up with a better solution though.
public class Investment {
public Investment()
{ }
public Investment(string name)
{
_name = name;
}
...}
[Serializable ( )]
public class Stock : Investment
{private string _ticker;
public Stock ( ) : base ( ) { }//<<<serialize requires parameterless
ctor
public Stock ( string name, string ticker )
: base ( name )
{
_ticker = ticker;
}
public string Ticker { get { return _ticker; } set { _ticker =
value; } }
}

Arne
 
A

Arne Vajhøj

i tried the following and got this error:
{"The type Investments.Model.Stock was not expected.
Use the XmlInclude or SoapInclude attribute to specify types that are not
known statically."}

Hm.

XmLSerializer can be a bit tricky with stuff like this.
*** typedefs ***
[Serializable ( )]

If you insert:

[XmlInclude(typeof(Stick)), XmlInclude(typeof(AnotherInvestment))]

here then it should work but that is not a nice solution.

I can not come up with a better solution though.

Try:

serializer = new XmlSerializer ( typeof (
List<Investment> ), new Type[] { typeof(Stock),
typeof(AnotherInvestment) } );

Arne
 
A

Arne Vajhøj

Right, and that is mentioned. (Basically, you can READ from the collection
but not change it.)

One can read, delete and add null. But one can not add
objects.

C# 4.0 interfaces with out type is about the same.

Demo:

using System;
using System.Collections.Generic;

namespace E
{
public class Investment
{

}
public class Stock : Investment
{

}
public class OtherInvestment : Investment
{

}
public interface IROList<out T>
{
T this[int ix]
{
get;
}
}
public class ROList<T,T2> : IROList<T> where T2 : T
{
private IList<T2> real;
public ROList(IList<T2> orig)
{
real = orig;
}
public T this[int ix]
{
get { return real[ix]; }
}
}
public class Program
{
public static void Main(string[] args)
{
//IList<Investment> lst = new List<Stock>();
IROList<Investment> lst1 = new ROList<Investment, Stock>(new
List<Stock>());
IROList<Investment> lst2 = new ROList<Investment,
OtherInvestment>(new List<OtherInvestment>());
Console.ReadKey();
}
}
}

Arne
 
M

mp

Arne Vajhøj said:
Try:

serializer = new XmlSerializer ( typeof (
List<Investment> ), new Type[] { typeof(Stock),
typeof(AnotherInvestment) } );

Arne

woo hoo!!! it works!!!
Thanks very much!
:)
private void btnGetData_Click(object sender, EventArgs e)
{
Debug.Print ( "Test store investment list" );
List< Investment > testlst = new List<Investment > ( );

for (int i = 0; i < 5; i++)
{ testlst.Add ( new Stock ( "Test " + i.ToString
( ),"Tick"+i.ToString() ) ); }

XMLStoreList.StoreInvestmentList ( testlst ,"TestListStore.xml");

Debug.Print ( "Now try to get it back " );
XMLStoreList.RetrieveInvestmentList (ref testlst,
"TestListStore.xml" );

ReadBackInvestmentList ( testlst );
}
private void ReadBackInvestmentList (List<Investment> testlst )
{
foreach(Stock stock in testlst)
{
Debug.Print("Stock {0}, {1}",stock.Name,stock.Ticker );
}
}

from output:
Test store investment list
Objects stored in TestListStore.xml
Now try to get it back
Stock Test 0, Tick0
Stock Test 1, Tick1
Stock Test 2, Tick2
Stock Test 3, Tick3
Stock Test 4, Tick4


fwiw
public static void StoreInvestmentList ( List<Investment> objectsList,
string fileName )
{
try
{
using (FileStream fStream = new FileStream ( fileName,
FileMode.Create ))
{
try
{
XmlSerializer serializer = new XmlSerializer ( typeof (
List<Investment> ),
new Type[] { typeof(Stock),
typeof(Bond ) } );

serializer.Serialize ( fStream, objectsList );
}
catch (Exception ex)
{
Debug.Print ( "Unable to Store objects in list...Problem
with XmlSerializer " );
Debug.Print ( ex.Message );
throw;
}
}
}
catch (Exception ex)
{
Debug.Print ( "Unable to StoreList of objects...Problem with
FileStream <" + fileName + ">" );
Debug.Print ( ex.Message );
throw;
}
Debug.Print ( "Objects stored in " + fileName );
}//storeInvestmentList

public static void RetrieveInvestmentList ( ref List<Investment>
objectsList, string fileName )
{
try
{
XmlSerializer serializer = new XmlSerializer ( typeof (
List<Investment> ),
new Type[] { typeof ( Stock ), typeof (
Bond ) } );

try
{
using (FileStream fStream = new FileStream ( fileName,
FileMode.Open ))
{
objectsList = (List<Investment>)serializer.Deserialize (
fStream );
}
}
catch (Exception ex)
{
Debug.Print ( "Failed Filestream " + ex.Message );
throw;
}

}
catch (Exception ex)
{
Debug.Print ( "Failed serialize to retrieve " + ex.Message );
throw;
}
}

thank you so much....i would never have figured that out!!!!!
mark
 
A

Arne Vajhøj

[...]
*** typedefs ***
[Serializable ( )]

If you insert:

[XmlInclude(typeof(Stick)), XmlInclude(typeof(AnotherInvestment))]

Presumably, that's supposed to be "typeof(Stock)" :)
Yes!

:)
here then it should work but that is not a nice solution.

I can not come up with a better solution though.

Try:

serializer = new XmlSerializer ( typeof (
List<Investment> ), new Type[] { typeof(Stock),
typeof(AnotherInvestment) } );

I'm curious if you prefer one or the other, and if so, why?

If definitely prefer the second.
I'm partial to the attributes approach myself, but that's just because
of my own aesthetic preference toward declarative solutions over
imperative ones. I admit to not seeing any particular technical
difference. Why do you say that using attributes is "not a nice solution"?

In the first case the base class actually need to have
a list of its sub classes. I think that is pretty bad from
a OO purist view. But worse from a practical view it is
impossible if the the base class is written as part
of a framework and then the sub classes has to be written
later.

In the second case one just need to know the list of potential
sub classes when doing the actual serialization. It seems
a bit more reasonable to expect the code serializing something
to know what it is serializing. Of course the serializing
code could also be in a framework not knowing the specific
sub classes, but then a good framework would (given how
XmLSerializer works) allow the client code to pass the
type array along.

Arne
 
M

mp

Arne Vajhøj said:


Of course the serializing
code could also be in a framework not knowing the specific
sub classes, but then a good framework would (given how
XmLSerializer works) allow the client code to pass the
type array along.

Arne

but how could one pass in a list of types and have the code
come up with
[XmlInclude(typeof(oneType)), XmlInclude(typeof(AnotherType))]

or is that not what you were saying?

and is that section inside the [] an attribute?


thanks
mark
 
A

Arne Vajhøj

Arne Vajhøj said:
On 1/21/11 6:26 PM, Arne Vajhøj wrote:
[...]


Of course the serializing
code could also be in a framework not knowing the specific
sub classes, but then a good framework would (given how
XmLSerializer works) allow the client code to pass the
type array along.

but how could one pass in a list of types and have the code
come up with
[XmlInclude(typeof(oneType)), XmlInclude(typeof(AnotherType))]

or is that not what you were saying?

That can not be done.

But you can pass it on to a method using the serializer.

As in:

public void ThisMethodOnlyKnowsAboutBaseClass(List<Investment> lst,
Type[] allsubtypes)
{
XmLSerializer ser = new XmlSerializer ( typeof (List<Investment> ),
allsubtypes);

so that the client code could do:

ThisMethodOnlyKnowsAboutBaseClass(lst, new Type[] { typeof(Stock),
typeof(AnotherInvestment) } );

Still not that nice. But it will work from a practical perspective.
and is that section inside the [] an attribute?

[] indicates an attribute.

Arne
 
M

mp

Arne Vajhøj said:
Arne Vajhøj said:
On 21-01-2011 23:20, Peter Duniho wrote:
On 1/21/11 6:26 PM, Arne Vajhøj wrote:
[...]


Of course the serializing
code could also be in a framework not knowing the specific
sub classes, but then a good framework would (given how
XmLSerializer works) allow the client code to pass the
type array along.

but how could one pass in a list of types and have the code
come up with
[XmlInclude(typeof(oneType)), XmlInclude(typeof(AnotherType))]

or is that not what you were saying?

That can not be done.

But you can pass it on to a method using the serializer.

As in:

public void ThisMethodOnlyKnowsAboutBaseClass(List<Investment> lst, Type[]
allsubtypes)
{
XmLSerializer ser = new XmlSerializer ( typeof (List<Investment> ),
allsubtypes);

so that the client code could do:

ThisMethodOnlyKnowsAboutBaseClass(lst, new Type[] { typeof(Stock),
typeof(AnotherInvestment) } );

Still not that nice. But it will work from a practical perspective.
and is that section inside the [] an attribute?

[] indicates an attribute.

Arne

ok, i see
thanks
mark
 

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