How i can get object in class List - c#

I created my class
class TxtEmail
{
public TxtEmail(string firtFirstmail, string domain)
{
this.Firstmail = firtFirstmail;
this.Domain = domain;
}
public string Firstmail { get; set; }
public string Domain { get; set; }
public string RetOneString()
{
return Firstmail + "#" + Domain;
}
}
Then my class add to List Class
class EmailDP : List<TxtEmail>
{
List<TxtEmail> txtemail = new List<TxtEmail>();
public void Add(string path)
{
txtemail.Add(new TxtEmail("user1", "google.ru"));
txtemail.Add(new TxtEmail("user5555", "google.com"));
txtemail.Add(new TxtEmail("user252", "outlook.com"));
txtemail.Add(new TxtEmail("user3", "gmail.com"));
}
another methods ......
But then i created object my classes, he show 0 Count, Why? Where i make mistake and how i can get object in it?
EmailDP em1 = new EmailDP();
MessageBox.Show(em1.Count.ToString()); -> this show 0
foreach (var myob in em1)
{
MessageBox.Show(myob.RetOneString());
}

You have two lists involved:
The class EmailDP itself derives from List<TxtEmail> and is therefore a list whose count you are displaying
The internal list txtemail to which you actually add the items, leaving EmailDP itself empty.
Change your class, so that it encapsulates the inner list.
class EmailDP
{
private readonly List<TxtEmail> _txtemail = new List<TxtEmail>();
public void Add(string path)
{
_txtemail.Add(new TxtEmail("user1", "google.ru"));
_txtemail.Add(new TxtEmail("user5555", "google.com"));
_txtemail.Add(new TxtEmail("user252", "outlook.com"));
_txtemail.Add(new TxtEmail("user3", "gmail.com"));
}
public int Count => _txtemail.Count;
public IEnumerable<TxtEmail> EmailTexts => _txtemail;
// ... other methods
}
And of course you have to call Add at least once...
EmailDP em1 = new EmailDP();
em1.Add("some path");
em1.Add("another path");
MessageBox.Show(em1.Count.ToString());
foreach (var myob in em1.EmailTexts)
{
MessageBox.Show(myob.RetOneString());
}
If you override ToString instead of creating a method RetOneString, you have the advantage that the TxtEmail objects will be displayed automatically at several places. I.e. in the debugger, in listboxes or in Console.WriteLine.
public override string ToString()
{
return Firstmail + "#" + Domain;
}

Your EmailDP is-a List and also has-a List and I don't think you mean for both of those to be true. It's a question of inheritance vs composition. Do you need your class to be a list or can it contain a list instead?
If you want your class to be-a List, then in your add method, you can do:
this.Add(new TxtEmail("user1", "google.ru")); ...
If you want your class to contain-a List then you can remove the inheritance of List
class EmailDP
{
...
And then make your list public so it is accessible:
public List<TxtEmail> txtemail = new List<TxtEmail>();
And then get the count from the list contained within:
MessageBox.Show(em1.textemail.Count.ToString());
Hope that helps.

You need to call the Add Method which fills your array.
Also do not inherit the List as you do not need this.
EmailDP em1 = new EmailDP();
em1.Add(string.Empty);
MessageBox.Show(em1.Count.ToString()); -> You will get items you added in the Add Method
foreach (var myob in em1)
{
MessageBox.Show(myob.RetOneString());
}

Related

Getting an object's list from inside another object

This is the layout
House -> HouseDef -> Room -> Door
L---> Windows
The problem is that any class may or may not have lists and nested classes like HouseDefinition does. The point is it should be flexible to handle any of these three cases for class variations:
1. hasList,
2. hasNestedObject with List inside that Nested Object
3. Has neither a List nor Nested class
Example of 1 being a Room class which contains a Window List
Example of 2 like House Class
Example of 3 like a Window Class
I have these two classes that I want to access generically from another class. I want to be able to get the Rooms List in House Definition by access of House class stored as an object in MyTreeNode. How can I do this not bound by types, or polymorphic to support a deeper hierarchy level in the future?
public class House
{
string name;
HouseDefinition definition;
public string Name() { return name; }
public HouseDefinition Definition {get {return definition;}}
public House(string name,HouseDefinition definition)
{
this.name = name;
this.definition = definition;
}
}
public class HouseDefinition
{
private List<Room> rooms = new List<Room>();
string type;
public List<Room> Rooms { get { return rooms; } }
public Room this[int i] { get { return rooms[i]; } }
public HouseDefinition(string type)
{
DefaultLayout();
this.type = type;
}
}
public class MyTreeNode : TreeNode
{
string label;
IEnumerable items;
bool hasList;
object item;
public string Label { get {return label; } }
public IEnumerable Items { get { return items;} }
public object Item { get { return item; } }
public bool HasList { get { return hasList; } }
public MyTreeNode(object item)
{
this.item = item;
label = item.ToString();
hasList = false;
}
public MyTreeNode(object item, IEnumerable Items)
{
this.item = item;
label = item.ToString();
hasList = true;
}
}
I think your classes look fine, but I would remove HouseDefinition, since those properties just seem like House to me. If you want to practice inheritance, you could create an IBuilding interface that forces House, Mansion, Shack to implement GetRooms() or something like that. A couple other things:
Your TreeNode class should be using generic types like public MyTreeNode(T item)
You should check out autoimplemented properties - the public fields automatically create private backing fields, so you don't need to create a private field and a getter like you did here: public object Item { get { return item; } }
it's considered bad practice to use the "object" type, so you should convert those to the generic types mentioned above
Good luck, your code is looking good so far!

Adding a property to a list c# that doesn't contain it

I have a method that returns a List of datatype <Reserva>. This class Reserva only has 4 properties which I can return with this method.
Within my diagram Reserva is a class that only is instanced within <Espectaculo>
I want to add a property to the new List I´m creating, for example I want to add the name of the Espectaculo: e.name
public List<Reserva> reservasNoPagas()
{
List<Reserva> reservasNoPagas = new List<Reserva>();
foreach (Espectaculo e in espectaculos)
{
reservasNoPagas.AddRange(e.reservasNoPagas());
//somewhere here I want to add e.name to the reservasNoPagas
}
return reservasNoPagas;
}
You can't add properties dynamically to classes. Inherit the class and add another in a new class:
public class ReservaExtended : Reserva
{
public string ExtraProperty { get; set; }
}

Method with generic return type but not generic input. Is this possible?

Suppose we have a NodeData class:
public class NodeData<T>
{
public string Name;
public T Value;
public NodeData(string name, T value)
{
this.Name = name;
this.Value = value;
}
}
And a base Node class and child classes that have several properties with type NodaData:
public class Node
{
public List<NodeData<T>> listOutputs<T>()
{
var fieldInfos = GetType().GetFields();
var list = new List<NodeData<T>>();
foreach (var item in fieldInfos)
{
Type t = item.FieldType;
string name = item.Name;
if (t == typeof(NodeData<T>))
{
var output = new NodeData<T>(name, default(T));
list.Add(output);
}
}
return list;
}
}
public class TestNode : Node {
public NodeData<int> data;
public NodeData<double> data2;
public NodeData<double> data3;
public TestNode ()
{
data = new NodeData<int>("test", 111);
data2 = new NodeData<double>("test", 113);
}
}
As you can see there is a method which lists all outputs with type T in the Node class So I can find what are the output fields of the child class in runtime:
TestNode node = new TestNode ();
var list = node.listOutputs<int>(); // this returns data
But I need to know how to use this method to list all NodeOutputs of any type T. In this example int and double. Do I need to add a method with this signature public List<NodeData<T>> listOutputs() // should return all properties data, data2, data3. Is it possible to have method like this? return type is generic but there is no type argument for method.
Even after your edit(s) it is not entirely clear what you are trying to achieve but here are my assumptions:
-You want to have some kind of Node object that acts as a container for different types of NodeData elements.
-You want to be able to return one list from this Node object that contains all NodeData elements stored in the Node container, regardless of the NodeData objects' type.
Instead of returning a List> object from the listOutputs methods, just return the non-generic version of the List object. Then you don't have to deal with T in the method call.
The logic that loops through the objects in the non-generic list can then examine the type to process the contained NodeData objects correctly.
Important note: My proposed solution is by no means pretty but I think it answers the question. In my opinion something is already seriously flawed from an OO point of view in the presented code (e.g. use of reflection) and a better solution would have to start by changing the underlying data structures. But that can only be done if we have more information how this is to be used, e.g. what kind of logic consumes the returned list.
You can create a base interface that will be used to return the generic data.
public interface INodeData
{
string Name { get; }
}
public class NodeData<T> : INodeData
{
public string Name { get; private set; }
public T Value { get; private set; }
public NodeData(string name, T value)
{
this.Name = name;
this.Value = value;
}
}
I modified the function to return a list of the interface. Doing this you won't depend on T.
public class Node
{
public List<INodeData> listOutputs()
{
var fieldInfos = GetType().GetFields();
var list = new List<INodeData>();
foreach (var item in fieldInfos)
{
INodeData data = GetType().GetField(item.Name).GetValue(this) as INodeData;
list.Add(data);
}
return list;
}
}
If you test the method, it should return the fields in a list. To work with a specific type, you can make use of is before using the type you search for.
public class TestNode : Node
{
public NodeData<int> data;
public NodeData<double> data2;
public NodeData<double> data3;
public TestNode()
{
data = new NodeData<int>("test", 111);
data2 = new NodeData<double>("test", 113);
}
}
private static void Main(string[] args)
{
TestNode node = new TestNode();
var list = node.listOutputs(); // this returns data
}
This may well be an XY problem, in that you probably want to rethink how you are designing your classes because using reflection in this way doesn't seem right. But give the problem you've presented, I'd tackle it like this:
public abstract class NodeDataBase
{
public string Name { get; set; }
public NodeData(string name)
{
this.Name = name;
}
// this isn't actually needed, but might be helpful
public abstract object GetValue();
}
public class NodeData<T> : NodeDataBase
{
public T Value { get; set; }
public NodeData(string name, T value) : base(name)
{
this.Value = value;
}
public override object GetValue()
{
return Value;
}
}
And now your method signature would be:
public List<NodeDataBase> listOutputs()
And with the list returned, you can use the GetValue method to get the actual values without needing to cast to the right generic type to be able to get at the Value property.
You could also just have a return type of List<object>, but then you'll have to cast each member of that list to the right generic type before you can access it's properties.
You can also avoid that nasty reflection code, instead of having data, data1, and data2, you could simply do this in your Node class:
public class Node
{
public List<NodeDataBase> Data { get; protected set; }
public Node()
{
Data = new List<NodeDataBase>();
}
}
And now you don't even need your listOutputs method because you can just get the list from the node (unless you actually wanted a copy, but that's fairly trivial to implement).
And you TestNode would be just:
public class TestNode : Node {
public TestNode ()
{
Data.Add(new NodeData<int>("test", 111));
Data.Add(new NodeData<double>("test", 113));
}
}

How to assign values to instances of type T?

I have some text files that are delimited by commas and I want to read a line, then instantiate it and assign values to the properties. The number of text files will grown in the future but now, I only need to work with a handful of them.
So I created a base class that'll take in a FileInfo argument, but the problem is how do I assign values to the instance? At the base class, it won't know what the properties names are. I think I should iterate through the properties and assign them by index, but t.GetType().GetProperties() doesn't return any items.
public class AccountDataFile : DataFileBase<AccountDataFile.Account>
{
public class Account
{
public string Name;
public string Type;
}
public AccountDataFile(FileInfo fiDataFile) : base(fiDataFile) { }
}
base class:
public class DataFileBase<T> where T : new()
{
public List<T> Data;
public DataFileBase(FileInfo fi)
{
this.Data = new List<T>();
var lines = fi.ReadLines();
foreach (var line in lines)
{
var tokens = line.Split(CONSTS.DELIMITER);
var t = new T();
// how to assign values to properties?
this.Data.Add(t);
}
}
}
Make the inheriting class provide the implementation:
public abstract class DataFileBase<T>
{
protected abstract T BuildInstance(string[] tokens);
}
public AccountDataFile : DataFileBase<AccountDataFile.Account>
{
protected override Account BuildInstance(string[] tokens)
{
var account = new Account();
account.Name = tokens[0]; // or whatever
return account;
}
}
You could add an abstract method to the base class to create the right kind of object. In your DataFileBase add a method like:
public abstract T CreateObject();
And implement it in AccountDataFile :
public override AccountDataFile.Account CreateObject() { new AccountDataFile.Account(); }
Consider existing CSV parser/reader for C#? .
If you still want to get your own - many serializers use attributes to do property to field name/column matches. I.e. annotate your Account type with ColumnAttribute, or similar custom attribute and read values at run-time. MSDN have article Accessing Attributes by Using Reflection covering reading attributes.
// starting point to read attributes:
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(myType);

How to create a property for a List<T>

private List<T> newList;
public List<T> NewList
{
get{return newList;}
set{newList = value;}
}
I want to create something like this, but this is won't work. it's just an example to demonstrate my goal as it's pretty common creating proprties for string and int and even T but I've never seen a List property
Is it even possible do such a thing, creating a property for type List ?
EDIT
I have a normal class that has normal properties (string properties, int properties, etc) but I have this property that stores user options, So on the presentation layer I had to convert them into a string so I could be able to store them in the Object. Now is it possible to have a property of type List to store the multivalues in a better and clean way, instead of converting information into one string and then split it and again join it! Thanks Again =D
EDIT2
private List<KeyValuePair<string, string>> _settings;
public List<KeyValuePair<string, string>> MySettings
{
get { return _settings; }
set { _settings = value; }
}
I used the exact code you posted but the property still won't appear in the object's instance, so I tried adding code in the get and set (I wonder why you left them empty or does it means something?) and also added a private variable in the class but still it doesn't appear in the properties of the object's instance!
I hope you could provide the exact code to implement this property and a simple code that assigns or retrieves from/to an instance of this class object
It's the first time to even hear about this KeyValuePair and all the tutorials are pretty simple and not for my case, sorry!
The Last Edit: After a lot of researching and the help of Mark Avenius I found the perfect answer. hope everyone can benefit from this.
NOW! HOW TO CREATE A PROPERTY FOR A LIST :
The Options Class
Public Class Options
{
private string id;
private int option;
public int ID
{
get { return id; }
set { id= value; }
}
public string Option
{
get { return option; }
set { option = value; }
}
}
The Users Class
public class Users
{
private int userId;
private string pass;
private List<Options> userOptions = new List<Options>();
public int ID
{
get { return userId; }
set { user = userId; }
}
public string Pass
{
get { return pass; }
set { pass = value; }
}
public List<Options> OptionsList
{
get { return userOptions; }
set { userOptions = value; }
}
}
The Presentation Layer
Users newUser = new Users ();
Options userOption = new Options ();
userOption.ID = int.Parse(txtBxID.Text);
userOption.Option = txtBxOption.Text;
Item.Options.Add(userOption);
T must be defined within the scope in which you are working. Therefore, what you have posted will work if your class is generic on T:
public class MyClass<T>
{
private List<T> newList;
public List<T> NewList
{
get{return newList;}
set{newList = value;}
}
}
Otherwise, you have to use a defined type.
EDIT: Per #lKashef's request, following is how to have a List property:
private List<int> newList;
public List<int> NewList
{
get{return newList;}
set{newList = value;}
}
This can go within a non-generic class.
Edit 2:
In response to your second question (in your edit), I would not recommend using a list for this type of data handling (if I am understanding you correctly). I would put the user settings in their own class (or struct, if you wish) and have a property of this type on your original class:
public class UserSettings
{
string FirstName { get; set; }
string LastName { get; set; }
// etc.
}
public class MyClass
{
string MyClassProperty1 { get; set; }
// etc.
UserSettings MySettings { get; set; }
}
This way, you have named properties that you can reference instead of an arbitrary index in a list. For example, you can reference MySettings.FirstName as opposed to MySettingsList[0].
Let me know if you have any further questions.
EDIT 3:
For the question in the comments, your property would be like this:
public class MyClass
{
public List<KeyValuePair<string, string>> MySettings { get; set; }
}
EDIT 4: Based on the question's edit 2, following is how I would use this:
public class MyClass
{
// note that this type of property declaration is called an "Automatic Property" and
// it means the same thing as you had written (the private backing variable is used behind the scenes, but you don't see it)
public List<KeyValuePair<string, string> MySettings { get; set; }
}
public class MyConsumingClass
{
public void MyMethod
{
MyClass myClass = new MyClass();
myClass.MySettings = new List<KeyValuePair<string, string>>();
myClass.MySettings.Add(new KeyValuePair<string, string>("SomeKeyValue", "SomeValue"));
// etc.
}
}
You mentioned that "the property still won't appear in the object's instance," and I am not sure what you mean. Does this property not appear in IntelliSense? Are you sure that you have created an instance of MyClass (like myClass.MySettings above), or are you trying to access it like a static property (like MyClass.MySettings)?
Simple and effective alternative:
public class ClassName
{
public List<dynamic> MyProperty { get; set; }
}
or
public class ClassName
{
public List<object> MyProperty { get; set; }
}
For differences see this post: List<Object> vs List<dynamic>
public class MyClass<T>
{
private List<T> list;
public List<T> MyList { get { return list; } set { list = value; } }
}
Then you can do something like
MyClass<int> instance1 = new MyClass<int>();
List<int> integers = instance1.MyList;
MyClass<Person> instance2 = new MyClass<Person>();
IEnumerable<Person> persons = instance2.MyList;
You could do this but the T generic parameter needs to be declared at the containing class:
public class Foo<T>
{
public List<T> NewList { get; set; }
}
It's possible to have a property of type List<T> but your class needs to be passed the T too.
public class ClassName<T>
{
public List<T> MyProperty { get; set; }
}
Either specify the type of T, or if you want to make it generic, you'll need to make the parent class generic.
public class MyClass<T>
{
etc

Categories