I have several classes that inhabit from this class:
public abstract class Class1
{
private string _protocol;
private static List<Plus> _class1Objects;
public string Protocol
{
get { return _protocol; }
set { _protocol = value; }
}
public static List<Plus> Class1Objects
{
get { return _class1Objects; }
set { _class1Objects = value; }
}
}
And the derive class:
public class Class2 : Plus
{
public bool name;
public int id;
}
public Webmail(string name, int id)
{
if (Class1Objects == null)
Class1Objects = new List<class1>();
.....
Class1Objects.Add(this);
}
And after my list is full of Class1Objects:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
if (Class1.Class1Objects[i].GetType() == typeof(Class2))
}
(Class2)Class1.Class1Objects[i].
}
}
Here after (Class2)Class1.Class1Objects[i]. i cannot see my Class2 memners
You need one additional paranthese:
((Class2)Class1.Class1Objects[i]).
At the moment it is read as the following:
(Class2)(Class1.Class1Objects[i].) //<= at the '.' it is still a class1
BUT as David said in his comment: If all are of type Class2 it should be a collection of that type and if not you should check the type, altogether with foreach:
foreach(var item in Class1.Class1Objects)
{
if(item is Class2)
((Class2)Class1.Class1Objects[i]).
}
It would be cleaner to use as:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
var c2 = Class1.Class1Objects[i] as Class2;
if (c2!=null)
}
c2.<whatever was meant to come after the .>
}
}
You might also want to consider switching to foreach unless there's a specific reason you want to manually extract each element from the List, e.g. if you're actually storing new values back into the list.
The correct syntax would be:
((Class2)Class1.Class1Objects[i]).name;
Because in your case, when you type something like this:
(Class2)Class1.Class1Objects[i].name;
You try to access the member name of Class1.Class1Objects[i], and only after that you try to cast it to Class2.
Also, the whole loop would be much simpler if you used foreach:
using System.Linq;
foreach(Class2 c in Class1.Class1Objects.OfType<Class2>())
{
Console.WriteLine(c.name); // or whatever you need to do with it
}
Related
Ive come across multiple questions and answers on here but none specific to my situation.
I have a class 'Entity' with multiple classes that extend off of it. I want the serialization to hit the list and understand and use the type of each item for the node name.
Now, I can use what is commented out (define each array item in the main class and define the name of such by using [XmlArrayItem("Subclass1", typeof(subclass1)] but I want to keep all definitions in their subclass and I will be having too many subclasses to define everything in the main entity class...Is there anyway to achieve this?
I have tried using [XmlType(TypeName="...")] for the subclasses and so on but that did not work.
[Serializable]
[XmlInclude(typeof(Subclass1))]
[XmlRoot("Entity")]
public class Entity{
[XmlArray("CausedBy")]
//[XmlArrayItem("Subclass1", typeof(subclass1))]
//[XmlArrayItem("Sublcass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
[XmlInclude(typeof(Subclass2))]
public class Subclass1:Entity{
//Code...
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2:Subclass1{
//Code...
}
Serializing the above code after creating an entity and adding a Subclass1 and Subclass2 to the list 'CausedBy' class results in the following:
<Entity>
<CausedBy>
<Entity ... xsi:type="SubClass1" />
<Entity ... xsi:type="SubClass2" />
</CausedBy>
<Entity>
I would like the output to show:
<Entity>
<CausedBy>
<SubClass1 .../>
<SubClass2 .../>
</CausedBy>
<Entity>
Since I totally failed to read the question to begin with, here's a new answer (it's a bit of a tl;dr, so you can always skip to the end and follow the link):
It isn't possible to get the built in serializer class to work because you don't wish to add the attributes that it needs to be able to operate. Your only option is to seralize the class yourself, however, this need not be as tedious as it sounds; I had a similar issue a few years ago with DataGridView in virtual mode and produced a generic virtualizer that could be used to virtualize the data for display; it used a custom attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class showColumnAttribute : System.Attribute
{
///<summary>Optional display format for column</summary>
public string Format;
///<summary>Optional Header string for column<para>Defaults to propety name</para></summary>
public string Title;
///<summary>Optional column edit flag - defaults to false</summary>
public bool ReadOnly;
///<summary>Optional column width</summary>
public int Width;
///<summary>
///Marks public properties that are to be displayed in columns
///</summary>
public showColumnAttribute()
{
Format = String.Empty;
Title = String.Empty;
ReadOnly = false;
Width = 0;
}
}
And a constructor:
///<summary>
///Extracts the properties of the supplied type that are to be displayed
///<para>The type must be a class or an InvalidOperationException will be thrown</para>
///</summary>
public Virtualiser(Type t)
{
if (!t.IsClass)
throw new InvalidOperationException("Supplied type is not a class");
List<VirtualColumnInfo> definedColumns = new List<VirtualColumnInfo>();
PropertyInfo[] ps = t.GetProperties();
MethodInfo mg, ms;
for (int i = 0; i < ps.Length; i++)
{
Object[] attr = ps[i].GetCustomAttributes(true);
if (attr.Length > 0)
{
foreach (var a in attr)
{
showColumnAttribute ca = a as showColumnAttribute;
if (ca != null)
{
mg = ps[i].GetGetMethod();
if (mg != null)
{
ms = ps[i].GetSetMethod();
definedColumns.Add
(
new VirtualColumnInfo
(
ps[i].Name, ca.Width, ca.ReadOnly, ca.Title == String.Empty ? ps[i].Name : ca.Title,
ca.Format, mg, ms
)
);
}
break;
}
}
}
}
if (definedColumns.Count > 0)
columns = definedColumns.ToArray();
}
This extracts the public properties of the class and supplies marked items to the DataGridView as columns together with a header, format, etc.
The effect of all of this (and the rest of the missing code) was that any type could be virtualized in a dataGridView simply by tagging public properties and calling the virtualizer once for a given type:
#region Virtualisation
static readonly Virtualiser Virtual = new Virtualiser(typeof(UserRecord));
[XmlIgnore] // just in case!
public static int ColumnCount { get { return Virtual.ColumnCount; } }
public static VirtualColumnInfo ColumnInfo(int column)
{
return Virtual.ColumnInfo(column);
}
public Object GetItem(int column)
{
return Virtual.GetItem(column, this);
}
/*
** The supplied item should be a string - it is up to this method to supply a valid value to the property
** setter (this is the simplest place to determine what this is and how it can be derived from a string).
*/
public void SetItem(int column, Object item)
{
String v = item as String;
int t = 0;
if (v == null)
return;
switch (Virtual.GetColumnPropertyName(column))
{
case "DisplayNumber":
if (!int.TryParse(v, out t))
t = 0;
item = t;
break;
}
try
{
Virtual.SetItem(column, this, item);
}
catch { }
}
#endregion
The number of columns, their properties and order can be specified automatically by creating a number of public properties derived from the class data:
#region Display columns
[showColumn(ReadOnly = true, Width = 100, Title = "Identification")]
public String DisplayIdent
{
get
{
return ident;
}
set
{
ident = value;
}
}
[showColumn(Width = 70, Title = "Number on Roll")]
public int DisplayNumber
{
get
{
return number;
}
set
{
number = value;
}
}
[showColumn(Width = -100, Title = "Name")]
public string DisplayName
{
get
{
return name == String.Empty ? "??" : name;
}
set
{
name = value;
}
}
#endregion
This would virtualize any class for dataGridView to display and edit data and I used it many times over the years and the extraction of properties to display is exactly what is required for XML serialization, indeed, it has a lot of the same characteristics.
I was going to adapt this method to do the same job for XML serialization but someone has already done it at https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=474453, I hope you can make use of this method to solve your problem.
This works for me:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Entity entity = new Entity();
entity.CausedBy = new List<Entity>();
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass1());
entity.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Test.txt"));
}
}
[Serializable]
[XmlRoot("Entity")]
public class Entity
{
[XmlArray("CausedBy")]
[XmlArrayItem("SubClass1", typeof(Subclass1))]
[XmlArrayItem("SubClass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
public class Subclass1 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToShortDateString();
public String SubClass1Item { get { return "Test1 " + t; } set { } }
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToString();
public String SubClass2Item { get { return "Test2 " + t; } set { } }
}
It produces:
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CausedBy>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
</CausedBy>
</Entity>
I have the following:
public class Broadcast {
public int NumUsersToMessage { get; set; }
public int NumMessagesQueued { get; set; }
public string DbUsersMessaged { get; set; }
public int NumMessagesSent {
get {
return UsersMessaged.Count();
}
}
public List<int> UsersMessaged {
get {
return DbUsersMessaged == null ? new List<int>() : DbUsersMessaged.Split(',').Select(Int32.Parse).ToList();
}
set {
DbUsersMessaged = value != null ? String.Join(",", value) : null;
}
}
}
My goal here is to only ever access DbUsersMessaged through UsersMessaged. I'm attempting to do broadcast.UsersMessaged.Add(2), however since this is not an assignment, I can't get the property to behave as I like. Instead, I have to do this:
tempList = broadcast.UsersMessaged();
tempList.Add(2);
broadcast.UsersMessaged = tempList;
db.SaveChanges();
Which is obviously unwieldy. I'm considering making an AddReassign extension method but I want to know - what's the standard practice here for supporting Lists of primitive types? It looks like even with the extension method, my best shot looks like this:
broadcast.UsersMessaged = broadcast.UsersMessaged.AddReassign(2) // yuck!
Before anyone asks - we've intentionally denormalized this for performance reasons.
If you don't care about performance, you can create own list:
public class MyList : IList<int>
{
private List<int> underlyingList;
private Broadcast entity;
public MyList(Broadcast entity)
{
this.entity = entity;
this.underlyingList = entity.DbUsersMessaged?.Split(",") ?? new List<int>();
}
public void Add(int i)
{
this.underlyingList.Add(i);
this.entity.DbUsersMessaged = String.Join(",", underylingList);
}
// other interface memebers impl
}
Then
MyList list;
public IList<int> UsersMessaged {
get {
return myList ?? (myList = new MyList(this));
}
}
Of course it is only sample.
I recommend you to have a look at this: Entity Framework 5 - Looking for Central Point to Execute Custom Code after Entity is Loaded from Database
And then convert from string to list, and then use Saving Changes event to convert back into the string construction when saving.
Then, for performance, maybe you want to use byte[] rather than a string for storing the data in the database.
The classes below consist of
A - father class
B - Child class
Holder - Contains a list of A's
I want to reach a child property from the list of fatherobjects. Why cant I do this? Or better question, how do I do this?
public class A
{
public int var = 0;
}
public class B : A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public B()
{
}
public B(B p_B)
{
Property1 = p_B.Property1;
Property2 = p_B.Property2;
}
}
class Holder
{
private List<A> m_Objects = new List<A>();
public void AddObject(A p_Object)
{
m_Objects.Add(p_Object);
}
public void AddObjectProperty1(B p_B)
{
// At this point, m_Objects holds a B-object. And I want to add the value from Property1
// but there is no Property1 in the A-class so I cant do this. How do I use the base.values from
// a statement like the one below?
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
if (index > -1)
m_Objects.ElementAt(index).Property1 += p_B.Property1;
}
}
class Program
{
static void Main(string[] args)
{
// Class to hold the objects
Holder h = new Holder();
// Create a B object
B b = new B();
b.Property1 = 1;
b.Property2 = 2;
// Place a new instance of the B-object in a list of A's
h.AddObject(new B(b));
// Add the value from Property1 to the value in the b-object in the a-list. :P
h.AddObjectProperty1(b);
Console.WriteLine(++b.var);
Console.ReadLine();
}
}
You can use type casting:
(m_Objects[i] as B).Property1
Or
((B)m_Objects[i]).Property1
At compile-time there is no possibility for the compiler to know, you would only add Bs to your list of As. So there is no guarantee whatsoever that each item in the following query is an instance of B and thus has Property1
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
First possibilty is casting as in Artyom's answer. But this will fail if you not all of the elements in the List are really Bs. So if you rely on all Elements in m_Objects to be instances of B, why don't you just use List<B> m_Objects?
If you need the mixed list, you have to do a type-check in the query to ensure, you are dealing with an instance of Bbefore casting.
int index = m_Objects.FindIndex(item => (item is B) && (item as B).Property1 == p_B.Property1);
See this DotNetFiddle Example
Hello I'm trying to retrun array type named ZverejnenyUcetType but the issue is that this array might contain two types : StandartniUcetType and NestandardniUcetType.
So the issue is when I try to return the array like this:
string[] dic_vstup = new string[] { (line) };
RozhraniWSDL.InformaceOPlatciType[] dic_vystup;
RozhraniWSDL.rozhraniCRPDPH srv = new RozhraniWSDL.rozhraniCRPDPH();
StatusType status = srv.getStatusNespolehlivyPlatce(dic_vstup, out dic_vystup);
string abc = status.bezVypisuUctu.ToString(); // If it is already a string, then ToString not needed
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
for (int x = 0; x <= 3; x++)
{
file2.WriteLine((((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "-"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "/"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).kodBanky));
}}
I get following exception: unable to cast object of type RozhraniWSDL.NestandardniUcetType to type RozhraniWSDL.StandardniUcetType.
NestandardniUcetType contains only one item - cislo
StandartníUcetType have 3 items- predcislo, cislo, kod banky
Here is an image of the array:
I thought that the solution might be to determinate which of the result are of type StandartniUcetType and which are NestandardniUcetType.
I would like to ask if this is possible to do?
I found this solution more common.
Thank you for your time.
If the array has two different types, you could add an if statement, like this:
if (info.zverejneneUcty[x].Item is RozhraniWSDL.StandardniUcetType) {
...
} else {
...
}
A slightly better approach would be to cast using the as operator, like this:
RozhraniWSDL.StandardniUcetType std = info.zverejneneUcty[x].Item as RozhraniWSDL.StandardniUcetType;
if (std != null) {
...
}
RozhraniWSDL.NestandardniUcetType nstd = info.zverejneneUcty[x].Item as RozhraniWSDL.NestandardniUcetType;
if (nstd != null) {
...
}
Finally, a very good approach would be writing two separate methods for the two types, and using dynamic to perform a dispatch. To do that, define two functions, like this:
static void WriteToFile(RozhraniWSDL.StandardniUcetType std, StreamWriter file) {
...
}
static void WriteToFile(RozhraniWSDL.NestandardniUcetType nstd, StreamWriter file) {
...
}
Now change your loop as follows:
for (int x = 0; x <= 3; x++) {
dynamic item = info.zverejneneUcty[x].Item;
WriteToFile(item, file2); // <<== Magic
}
Using the OfType extension method over the array will filter for the type you need
foreach (var item in info.zverejneneUcty.OfType<RozhraniWSDL.StandardniUcetType>())
{
file2.WriteLine(item.predcislo + "-" + item.cislo + "-" + item.kodBanky);
}
I'd redesign the types and remove the issue instead, through an abstract class, like this:
// I'm making up the inner types, adapt this to your code
public abstract class UcetType
{
public virtual object predcislo { get; set; }
public virtual object cislo { get; set; }
public virtual object kodBanky { get; set; }
public virtual void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// considering all properties
// this acts as "default" for this type and all derived ones
}
}
public class StandardniUcetType : UcetType
{
// This will use the abstract as-is
// with all 3 properties and the "default" WriteToFile() method
}
public class NestandardniUcetType : UcetType
{
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object predcislo
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object kodBanky
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
// change the way WriteToFile behaves
public override void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// only considering 'cislo' property
}
}
// Usage example, based on question
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
// I assume "3" is the expected length of the array ? Change the for like this:
for (int x = 0; x <= info.zverejneneUcty.Length; x++)
{
//Delegate to the WriteToFile() method the task to build and write the line!
info.zverejneneUcty[x].Item.WriteToFile(file2);
}
}
I see no benefit in a dynamic approach here. This is more readable and easy to expand in the future (need a new type ? just derive UcetType in a new class and override away).
I have a class MySet
class MySet
{
.......
}
This class will declare a reference to another type
(i.e)
class MySubSet
{
....
}
The purpose of the type MySubset is to supply "subset id" and a collection of integers to
the type MySet.
Which one of the followings is the correct implementation
(1)
class MySet
{
int mySetID;
MySubSet subset = new MySubSet();
public int MySetID
{
get { return mySetID; }
set { mySetID = value; }
}
public MySubSet MySubSet
{
get { return subset; }
set { subset = value; }
}
}
class MySubSet
{
int subsetID;
List<int> subset = new List<int>();
public List<int> SubSet
{
get { return subset; }
set { subset = value; }
}
public int SubSetID
{
get { return subsetID; }
set { subsetID = value; }
}
}
(2)
class MySet
{
int mySetID;
AnotherSubSet subset = new AnotherSubSet();
public int MySetID
{
get { return mySetID; }
set { mySetID = value; }
}
public AnotherSubSet MySubSet
{
get { return subset; }
set { subset = value; }
}
}
class AnotherSubSet : List<int>
{
int subsetID;
List<int> lst = new List<int>();
public int SubSetID
{
get { return subsetID; }
set { subsetID = value; }
}
}
If both are worst design consideration help me to implement the one that I could follow.
MySet doesn't look like a collection to me. It's just a class.
I'd rename it to ´MyEntity´or something like that.
List<MyEntity> mySet = new List<MyEntity>();
From all the information you've provided, I would do this:
public class MyEntity
{
public int ID { get; set; } // shortcut
public List<int> Numbers = new List<int> { get; set; } // shortcut
}
Sorry, I don't have /Net3.0 to hand so can't check the constructor of the list with the shortcut get/set but its the theory that counts...
The first version is better (as improved upon by ck) - use composition instead of inheritance. You are advised not to add properties to collections, which is effectively what you're doing in version 2. Collections should contain their items only. Someone else may be able to expand on the reasons for this, as I am not an expert, but it does cause serialization problems.
Number 2 is better, use inheritence not composition for this pattern, - because fundementally, it is a collection. It does not contain a collection. Inheritance gives you all the functionality of the base class without the need to write pass-through functions. If you want to add a new item to the collection, using composition, you either have to add a pass through method for the Add() method to class MySubSet:
class MySubSet
{
int subsetID;
List<int> subset = new List<int>();
public List<int> SubSet
{
get { return subset; }
set { subset = value; }
}
public void Add(int i) { subset.Add(i); } // pass through to subset.Add()
}
or you have to use the following non-intuitive and confusing syntax...
MySet.MySubSet.SubSet.Add(67);
with inheritence, all you need is
MySet.MySubSet.Add(67);