Why I can not cast? - c#

public abstrct class Item
{
public string Name {get;set;}
}
public class Music : Item
{
public double Price {get;set;}
}
public class Game : Item
{
public string Image {get;set;}
}
public class Inventory
{
private IList<Item> _games;
private IList<Item> _musics;
public Inventory()
{
_games = new List<Item>();
_musics = new List<Item>();
}
public void Add<T>(T item) where T : Item
{
if(typeof(T) == typeof(Game))
{
_game.add(item);
}
if(typeof(T) == typeof(Music))
{
_muisc.add(item);
}
public List<T> GetCollection<T>() where T : Item
{
return (List<T>) _muiscs;
}
class Porgram
{
static void Main(string[] args)
{
Inventory inventory = new Inventory();
var music1 = new Music(){ Name ="aa", Price = 10};
var Music2 = new Music() { Name ="bb", price = 20 };
inventory.add(music1);
inventory.add(music2);
List<Music> myMusics = inventory.GetCollection<Music>();
}
The code will compile but it will throw exception when try to Call Get Collection method.
I am not sure really why? I am guess i am using generic incorrect.

A List<Item> cannot be cast to a List<Music>. While Music is a subclass of Item, generic types do not follow the same inheritance pattern as their collection type. The simplest way to fix your code would be to replace the cast in your GetCollection method with a call to the Linq extension method cast, followed by ToList. That said, I think your entire class could be redesigned to handle this sort of inheritence better.
So, your GetCollection method looks like this:
public List<T> GetCollection<T>() where T : Item
{
return _musics.Cast<T>().ToList();
}

Try this code:
public abstract class Item
{
public string Name { get; set; }
}
public class Music : Item
{
public double Price { get; set; }
}
public class Game : Item
{
public string Image { get; set; }
}
public class Inventory<E> where E : Item
{
private IList<E> _games;
private IList<E> _musics;
public Inventory()
{
_games = new List<E>();
_musics = new List<E>();
}
public void Add(E item)
{
if (typeof(E) == typeof(Game))
{
_games.Add(item);
}
if (typeof(E) == typeof(Music))
{
_musics.Add(item);
}
}
public List<E> GetCollection()
{
return _musics;
}
}
public class Program
{
public static void Main(string[] args)
{
Inventory<Item> inventory = new Inventory<Item>();
var music1 = new Music() { Name = "aa", Price = 10 };
var music2 = new Music() { Name = "bb", Price = 20 };
inventory.Add(music1);
inventory.Add(music2);
List<Item> myMusics = inventory.GetCollection();
}
}
You need to declare your Inventory class to be generic where it takes in a class that extend Item
Also: It looks like you wrote the code, and didn't copy and paste it... I don't know why you did that...

Just modify your GetCollection method as
public List <T> GetCollection<T>() where T :Item
{
if (typeof(T) == typeof(Game))
{
return _games.Cast<T>().ToList();
}
if (typeof(T) == typeof(Music))
{
return _musics.Cast<T>().ToList(); ;
}
return null;
}

Related

Constructor chain creates object, but is null in caller

Here's what I have:
public partial class MainWindow : Window
{
IMainUIHandler MainUIHandler;
public MainWindow()
{
//InitializeComponent();
IMainUIHandler UIHandlerMain = new MainUIHandler();
UIHandlerMain.PlayerMgtHandler.AddNewPlayer("2020", "_", 1, 3);
... more stuff
}
}
class MainUIHandler : IMainUIHandler
{
public IPlayerMgtUIHandler PlayerMgtHandler { get; }
public MainUIHandler()
{
PlayerMgtHandler = new PlayerMgtUIHandler();
}
}
class PlayerMgtUIHandler : IPlayerMgtUIHandler
{
public List<IPlayer> NewPlayers { get; } //TODO change List to HashSet
public void AddNewPlayer(string idPrefix, string idSeparator, int idSeqNumber,int idNumDigits)
{
IPlayer player=new Player(idPrefix,idSeparator,idSeqNumber,idNumDigits);
NewPlayers.Add(player);
}
public PlayerMgtUIHandler()
{
List<IPlayer> NewPlayers = new List<IPlayer>();
}
}
Stepping through beginning at MainWindow from IMainUIHandler UIHandlerMain = new MainUIHandler();, when I get to:
public PlayerMgtUIHandler()
{
List<IPlayer> NewPlayers = new List<IPlayer>();
}
the List<IPlayer> NewPlayers is not nothing; it has zero elements. When I step out back to the caller PlayerMgtHandler.NewPlayers is null.
What am I doing wrong?
Changed class PlayerMgtUIHandler to:
class PlayerMgtUIHandler : IPlayerMgtUIHandler
{
public List<IPlayer> NewPlayers { get; protected set; } //TODO change List to HashSet
public void AddNewPlayer(string idPrefix, string idSeparator, int idSeqNumber,int idNumDigits)
{
IPlayer player=new Player(idPrefix,idSeparator,idSeqNumber,idNumDigits);
NewPlayers.Add(player);
}
public PlayerMgtUIHandler()
{
NewPlayers = new List<IPlayer>();
}
}
Now it works as I wanted. Thanks for pointing me in the right direction.

how to add object directly to nested ienumerable collection object group by Error- Cannot convert List to Collection

Hi I have created few nested iEnumerable implemented classes.
CDSWorkflowCollection
CDSModuleCollection
CDSSystemCollection
Below are my Classes
public class cdssystems
{
public string cdsSystemName;
public CDSModuleCollection listModules;
}
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
class cdsdelgate
{
private string delgateName;
private DateTime fromDate;
private DateTime toDate;
private string functionElement;
private CDSSystemCollection cdsSystemsList;
private string cdsComments;
private string JobTitle;
}
public class cdsworkflows
{
public string WorkflowName;
public string ActionGroup;
}
class CDSWorkflowCollection : ICollection, IEnumerable<cdsworkflows>
{
private List<cdsworkflows> cdsWorkflowList;
private readonly object syncObject = new object();
public CDSWorkflowCollection(IEnumerable<cdsworkflows> cdsWorkflowList)
: base()
{
this.cdsWorkflowList = new List<cdsworkflows>(cdsWorkflowList);
}
public IEnumerator<cdsworkflows> GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
if ((array.Rank != 1) || ((this.Count + index) > array.Length))
{
throw new ArgumentException();
}
int count = 0;
foreach (cdsworkflows cssWorkflow in this.cdsWorkflowList)
{
array.SetValue(cssWorkflow, count++);
}
}
public int Count
{
get
{
return this.cdsWorkflowList.Count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this.syncObject;
}
}
}
class CDSSystemCollection : ICollection, IEnumerable<cdssystems>
{
private List<cdssystems> cdsSystemList;
private readonly object syncObject = new object();
public CDSSystemCollection(IEnumerable<cdssystems> cdsSystemList)
: base()
{
this.cdsSystemList = new List<cdssystems>(cdsSystemList);
}
//Rest of the code here
}
class CDSDelegateCollection : ICollection, IEnumerable<cdsdelgate>
{
private List<cdsdelgate> cdsDelegateist;
private readonly object syncObject = new object();
public CDSDelegateCollection(IEnumerable<cdsdelgate> cdsDelegateList)
: base()
{
this.cdsDelegateist = new List<cdsdelgate>(cdsDelegateList);
}
//Rest of the code here
}
No i want to add objects to the class using group by and my code goes like below
var results = (from SPListItem item in myItemsList
group item by item["Systems"]
into grp
select new cdssystems()
{
cdsSystemName = grp.Key.ToString(),
listModules = (from item in grp
group item by item["Modules"]
into grpModules
select new cdsmodules()
{
moduleName = grpModules.Key.ToString(),
listWorkflows = (from item in grpModules
group item by item["Workflows"]
into grpWorkflows
select new cdsworkflows()
{
WorkflowName = grpWorkflows.Key.ToString(),
ActionGroup = grpWorkflows.FirstOrDefault()["ActionGroup"].ToString()
}
).ToList()
}).ToList()
}).ToList();
I am getting Error in ToList() saying
Cannot implicitly convert type 'System.Collections.Generic.List' to 'CDS.BusinessObjects.CDSWorkflowCollection'
I know the parm expects a collection and i am passing List. How to pass the collection. Please help
Delete your custom collection types and use the Generic ones from the .net framework instead. You can use List<T>, IList<T>, or ICollection<T>. There is almost never a need to write your own collection implementation(s).
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
becomes
public class cdsmodules
{
public string moduleName { get; set; }
public List<cdsworkflows> listWorkflows { get; set; }
}
You should also follow proper visibility guidelines by never exposing fields directly. Instead use a property with a get;set; accessor. Fields should almost always be scoped as private or protected.

Using LINQ: How To Return Array Of Properties from a Class Collection?

Here is a Basic Class with TheProperty in question:
class BasicClass {
public BasicClass() {
TheProperty = new Object();
Stamped = DateTime.Now;
}
public object TheProperty { get; set; }
public DateTime Stamped { get; private set; }
}
Here is the Basic List:
class BasicList {
private List<BasicClass> list;
public BasicList() {
list = new List<BasicClass>();
}
public BasicClass this[object obj] {
get { return list.SingleOrDefault(o => o.TheProperty == obj); }
}
public void Add(BasicClass item) {
if (!Contains(item.TheProperty)) {
list.Add(item);
}
}
public bool Contains(object obj) {
return list.Any(o => o.TheProperty == obj); // Picked this little gem up yesterday!
}
public int Count { get { return list.Count; } }
}
I'd like to add a class to BasicList that will return an array of items.
I could write it like this, using traditional C#:
public object[] Properties() {
var props = new List<Object>(list.Count);
foreach (var item in list) {
props.Add(item.TheProperty);
}
return props.ToArray();
}
...but how would I write that using a LINQ or Lambda query?
return list.Select(p=>p.TheProperty).ToArray()

List Covariance results in duplication of code

I have 2 independent classes A and B and I have a Storage class which manages the storage of objects of type A and B.
I am trying to abstract the code that does the Store of A and B, however I am stuck due to List covariance I could not assign List<object> objList = new List<A>(); in the following code.
[DataContract]
public class A {
public int UID;
}
[DataContract]
public class B {
public int UID;
}
public class Storage {
public void Store(A a) {
List<A> aList = ReadA();
if (aList == null) {
aList = new List<A>();
}
aList.Add(a);
WriteNodes(aList);
}
public void StoreB(B b) {
List<B> bList = ReadB();
if (bList == null) {
bList = new List<B>();
}
bList.Add(b);
WriteNodes(bList);
}
public List<A> ReadA() {
//deserializes from aFileName and returns List<A>
}
public List<B> ReadB() {
//deserializes from bFileName adn returns List<B>
}
private static void WriteNodes<T>(List<T> nodeList) {
FileStream fs = new FileStream(aFileName, FileMode.Create);
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
DataContractSerializer ser =
new DataContractSerializer(typeof(List<T>));
ser.WriteObject(writer, nodeList);
writer.Close();
fs.Close();
}
}
If you look at StoreA and StoreB methods they have a generic pattern except for the type that is used. ReadA and ReadB are no problem I could just take the type as another parameter and create a single function Read.
So is it possible to create an abstraction for Store so I don't end up with StoreA and StoreB methods?
What about:
public void Store<T>(T a) {
List<T> aList = Read<T>();
if (aList == null) {
aList = new List<T>();
}
aList.Add(a);
WriteNodes(aList);
}
public List<T> Read<T>() {
//Read a or b depend on T
}
Yes, you can do it by introducing common interface for items to be sotred and extract item type into enum.
STORAGE
public class Storage
{
public Storage()
{
// create it once on construction stage
// so you do not need to check for null each time in Sore()/Read()
this.AllItems = new List<IItem>();
}
public IList<IItem> AllItems { get; private set; }
public void Store<TItem>(TItem item)
where TItem: IItem
{
this.AllItems.Add(item);
}
public IEnumerable<IItem> Read(StorageItemType itemType)
{
return this.AllItems.Where(item => item.ItemType == itemType);
}
}
Abstract Storage Item type (more generic solution):
// Item types
enum StorageItemType
{
A,
B
}
interface IItem
{
int UID { get; }
StorageItemType ItemType { get; }
}
public abstract class StorageItemBase: IItem
{
public int UID { get; private set; }
public abstract StorageItemType ItemType
}
public sealed class B : StorageItemBase
{
public override StorageItemType ItemType
{
get
{
return StorageItemType.B; // !!!
}
}
}

IEnumerable collection to List

I've written a CustomerCollection class, which implements the IEnumerable and IEnumerator interfaces. Now I want the CustomerCollection class object to be searchable by Where() And Find() function and also would like to get a List object of type Customer From the CustomerCollection class. Please help. Also, is the implementation of the interfaces right.
public class Customer
{
private int _CustomerID;
private string _CustomerName;
public Customer(int customerID)
{
this._CustomerID = customerID;
}
public int CustomerID
{
get
{
return _CustomerID;
}
set
{
_CustomerID = value;
}
}
public string CustomerName
{
get
{
return _CustomerName;
}
set
{
_CustomerName = value;
}
}
}
public class CustomerController
{
public ArrayList PopulateCustomer()
{
ArrayList Temp = new ArrayList();
Customer _Customer1 = new Customer(1);
Customer _Customer2 = new Customer(2);
_Customer1.CustomerName = "Soham Dasgupta";
_Customer2.CustomerName = "Bappa Sarkar";
Temp.Add(_Customer1);
Temp.Add(_Customer2);
return Temp;
}
}
public class CustomerCollection : IEnumerable, IEnumerator
{
ArrayList Customers = null;
IEnumerator CustomerEnum = null;
public CustomerCollection()
{
this.Customers = new CustomerController().PopulateCustomer();
this.CustomerEnum = Customers.GetEnumerator();
}
public void SortByName()
{
this.Reset();
}
public void SortByID()
{
this.Reset();
}
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)this;
}
public void Reset()
{
CustomerEnum.Reset();
}
public bool MoveNext()
{
return CustomerEnum.MoveNext();
}
public object Current
{
get
{
return (Customer)CustomerEnum.Current;
}
}
}
You can call Cast<Customer>() on your IEnumerable which will give you an IEnumerable<Customer>, or just implement IEnumerable<Customer> to begin with. LINQ is almost entirely hooked into IEnumerable<T>, not IEnumerable. Once you did that you'd get all the LINQ to objects goodness for free.
I recommend to use OfType<T>() instead of Cast<T>() because if your collection contains T1 and T2, collection.Cast<T1>() will throw an error while collection.OfType<T1>() will return IEnumerable<T1> contains only instances of T1 not T2
This will do what you want. Note, I have abstracted out the IEnumerable to make it reusable and reduced the complexity of all of the other classes.
//Write your Test first
public class Test
{
public void TestEnumerator()
{
var customers = new CustomerCollection();
var qry =
from c in customers
select c;
foreach (var c in qry)
{
Console.WriteLine(c.CustomerName);
}
//Create a new list from the collection:
var customerList = new List<Customer>(customers);
}
}
public abstract class MyColl<T> : IEnumerable<T>
{
protected T[] Items;
public IEnumerator<T> GetEnumerator()
{
foreach (T item in Items)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Customer
{
public Customer(int customerID)
{
CustomerID = customerID;
}
public int CustomerID { get; set; }
public string CustomerName { get; set; }
}
public class CustomerController
{
public Customer[] PopulateCustomer() {
return new [] {new Customer(1) {CustomerName = "Soham Dasgupta"},
new Customer(2) {CustomerName = "Bappa Sarkar"}};
}
}
public class CustomerCollection : MyColl<Customer>
{
public CustomerCollection()
{
Items = new CustomerController().PopulateCustomer();
}
}
public class CustomerController
{
public List<Customer> PopulateCustomer()
{
List<Customer> Temp = new ArrayList();
Customer _Customer1 = new Customer(1);
Customer _Customer2 = new Customer(2);
_Customer1.CustomerName = "Soham Dasgupta";
_Customer2.CustomerName = "Bappa Sarkar";
Temp.Add(_Customer1);
Temp.Add(_Customer2);
return Temp;
}
}
public class CustomerCollection : List<Customer>
{
List<Customer> Customers = new List<Customer>();
public CustomerCollection()
{
this.Customers = new CustomerController().PopulateCustomer();
}
}
new List<Customer>(myCustomerEnumerator);
The recommended base class to use for creating your own collection implementations is System.Collections.ObjectModel.Collection<T>
(from MSDN)
This base class is provided to make it easier for implementers to create a custom collection. Implementers are encouraged to extend this base class instead of creating their own.
public class CustomerCollection : Collection<Customer>
{
}

Categories

Resources