can we declare an object of another class as the data member - c#

My code is like this...
class Transaction
{
public class Date
{
public int day, month, year;
}
Date d;
double amount;
long acc_no;
string action;
}
how can we access the Date d.

how can we access the Date d
Same way you access any class-level member of any object.
From within any instance of the class Transaction, you would access it as a class-level member:
this.d
From outside an instance of Transaction you can't access d (nor should you) because it's a private member. (C# members are private by default unless declared otherwise.)
From within an instance of Date there's no guarantee that you're in the context of an instance of Transaction so there's no direct access to that member. (Just because it's a nested class doesn't guarantee that it will always be used in that structure.) Not that it would really matter anyway since d is an instance of Date so if you're in Date then it would only need to access itself anyway.

Like mentioned in the comment, this is generally not a good idea, but you can access it. You can access it from anywhere in class Transaction, but not outside it, unless you use a method or property.
class Transaction
{
public class Date
{
public int day, month, year;
}
Date d;
double amount;
long acc_no;
string action;
public Date GetDate()
{
return d; // Access Date d by using a method
}
}

namespace banking
{
public class Transaction
{
public class Date
{
public int day, month, year;
}
public Date date = new Date();
public double amount;
public long acc_no;
public string action;
}
class Program
{
static void Main(string[] args)
{
List<Transaction> transaction = new List<Transaction>();
StreamReader sr = new StreamReader("transaction.csv");
string data = sr.ReadLine();
while (data != null)
{
string[] dataarray = data.Split(',');
string[] date_split = dataarray[0].Split('-');
Transaction tran_obj = new Transaction();
tran_obj.date.day = int.Parse(date_split[0]);
tran_obj.date.month = int.Parse(date_split[1]);
tran_obj.date.year = int.Parse(date_split[2]);
tran_obj.acc_no = long.Parse(dataarray[1]);
tran_obj.amount = double.Parse(dataarray[2]);
tran_obj.action = dataarray[3];
transaction.Add(tran_obj);
data = sr.ReadLine();
}
Console.WriteLine("Please enter the account number for which you are looking for");
long new_acc_no = long.Parse(Console.ReadLine());
foreach (Transaction t in transaction)
{
if (t.acc_no == new_acc_no)
{
Console.WriteLine(t.amount);
Console.WriteLine(t.date);
Console.WriteLine(t.action);
}
}
string s = Console.ReadLine();
}
string s = Console.ReadLine();
}
}
the problem with this code is that in output console it is not showing the date
i have stored the date like this 12-02-1994

Related

C# Retrieving data and storing it in a list

I've been trying to learn some C# by creating a basic banking application that allows a user to add a current or savings account. If it's a current account then it multiplies the starting balance by 0.2 and if its a savings, then it multiples by 0.6. When they add an account, the application should save it to a list and finally display all the account names. So far I have a the form which allows the user to add an account called AddAccount.cs. I then have an Account.cs which should set the account and then a AccountList.cs which adds it to a list.
What I need help with:
How do I pass the new account details and set them in the Account.cs?
How then to add the account to the list and display the name of the Account?
Account.cs:
abstract class Account
{
public string accName, accId, accType;
public double balance;
public void setValues(string name, string id, double bal, string type)
{
this.accName = name;
this.accId = id;
this.balance = bal;
this.accType = type;
}
}
class CurrentAccount : Account
{
public double interst()
{
return balance * 0.2;
}
}
class SavingsAccount : Account
{
public double interst()
{
return balance * 0.6;
}
}
AddAccount.cs:
private void btn_AddAccount_Click(object sender, EventArgs e)
{
string name, id, type;
double balance;
name = input_AccountName.Text;
id = input_AccountNo.Text;
balance = Convert.ToDouble(input_StartBalance.Text);
if (radio_CurrentAccount.Checked)
{
type = "C";
}
else
{
type = "S";
}
//closes the form when clicked
this.Close();
}
AccountList.cs:
class AccountList
{
private List<Account> accountlst;
public List<Account> AccountLst
{
get { return accountlst; }
}
}
Please let me know if I'm completely wrong. Even the slightest bit of help would be appreciated.
Well assuming that if type is "C" then you create an object of type current account and if type is "S" then you create a savings account it would look something like this (by the way im going to do this in pseudo-code):
if (type is C)
Create new CurrentAccount object
call setValues(name, id, bal, type) //these are the local variable you created in AddAccount.cs
getAccountlst().add(CurrentAccount object you created) //adds to list
else
Create new SavingsAccount object
call setValues(name, id, bal, type)
getAccountlst().add(SavingsAccount object you created) //adds to list
By the way 2 problems, since you never initialized the accountlst object inside AccountList.cs by calling the new operator, it is set to null, so when you call getAccountlst() it will return a null object and if you try to add to it you will get a null pointer exception! And the pther problem, Since your AccountList.cs has to be initialized with new operator, you can lose your information inside your list, to fix this you can do something like:
static class AccountList {
List<Account> accountList = new List<Account>();
public List<Account> Accountlst {
get {
return accountList;
}
}
}
Now to add to your list all you have to do is AccountList.Accountlst.add(Account object here);

Looping to Create and Add New Objects to ArrayList

Edit to save you from reading through this whole post
tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field
I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:
create ArrayList of Blogs
loop (some condition)
create new Blog
add this Blog to AL
However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:
public static ArrayList AllBlogs()
{
SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
ArrayList allBlogs = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
}
dr.Close();
return allBlogs;
}
As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?
Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:
Blog object has id, title, and message fields and their respective getter/setters
Kristina_Blogs is a table representing these blogs with columns for id, title, message
The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
This code works perfectly when I use an ArrayList of Strings instead of Blogs
Edit: Including the code from Blog class
public class Blog
{
public App myApp;
public static string Title;
public static string Message;
public static int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public string getTitle() { return Title; }
public void setTitle(string t) { Title = t; }
}
The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
}
And fill your list this way, don't forget to add using System.Linq;:
var result = new List<Blog>();
var connection = #"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
.ForEach(row =>
{
var b = new Blog();
b.Id = row.Field<int>("Id");
b.Title = row.Field<string>("Title");
b.Message = row.Field<string>("Message");
result.Add(b);
});
return result;
Note:
When you create a member static, it is shared between all instances of that calss.
In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:
Property:
private int id;
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
or more simple:
public int Id { get; set; }
All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.
Remove the static attributes from your class:
public class Blog
{
public App myApp;
public String Title;
public String Message;
public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }
}
When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.
Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.
I would make a quick method to prevent null value from throwing error
public static string GetSafeString(SqlDataReader reader, int index)
{
if (!reader.IsDBNull(index))
return reader.GetString(index);
else
return string.Empty;
}
Replace this code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
With This Code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setId(dr.GetInt32(0));
b.setTitle(GetSafeString(dr, 1);
b.setMessage(GetSafeString(dr, 2);
allBlogs.Add(b);
}
Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.

Mapping TimeSpan in SQLite and Dapper

I'm attempting to use Dapper to interface to an existing database format that has a table with a duration encoded as ticks in a BIGINT column. How do I tell Dapper to map my POCO's TimeSpan-typed property to ticks when inserting into and reading from the database?
I've tried to set the type map for TimeSpan to DbType.Int64:
SqlMapper.AddTypeMap(typeof(TimeSpan), DbType.Int64);
And I've also created an ITypeHandler, but the SetValue method is never called:
public class TimeSpanToTicksHandler : SqlMapper.TypeHandler<TimeSpan>
{
public override TimeSpan Parse(object value)
{
return new TimeSpan((long)value);
}
public override void SetValue(IDbDataParameter parameter, TimeSpan value)
{
parameter.Value = value.Ticks;
}
}
Here's my POCO:
public class Task
{
public TimeSpan Duration { get; set; }
// etc.
}
When executing a simple insert statement like this:
string sql = "INSERT INTO Tasks (Duration) values (#Duration);";
And passing the POCO as the object to insert:
Task task = new Task { Duration = TimeSpan.FromSeconds(20) };
connection.Execute(sql, task);
I get this exception:
System.InvalidCastException : Unable to cast object of type 'System.TimeSpan' to type 'System.IConvertible'.
at System.Convert.ToInt64(Object value, IFormatProvider provider)
at System.Data.SQLite.SQLiteStatement.BindParameter(Int32 index, SQLiteParameter param)
at System.Data.SQLite.SQLiteStatement.BindParameters()
at System.Data.SQLite.SQLiteCommand.BuildNextCommand()
at System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at Dapper.SqlMapper.ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action`2 paramReader) in SqlMapper.cs: line 3310
at Dapper.SqlMapper.ExecuteImpl(IDbConnection cnn, ref CommandDefinition command) in SqlMapper.cs: line 1310
at Dapper.SqlMapper.Execute(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable`1 commandTimeout, Nullable`1 commandType) in SqlMapper.cs: line 1185
If I leave the TimeSpan type mapping as-is (it defaults to DbType.Time), it writes the string version of the TimeSpan, i.e. `00:00:20.000", which isn't helpful as it does not match the format of the other data in the column.
Could you do the following instead?
public class Task
{
public TimeSpan Duration { get; set; }
public long Ticks
{
get { return Duration.Ticks; }
set { Duration = new TimeSpan(value); }
}
// etc.
}
string sql = "INSERT INTO Tasks (Duration) values (#Ticks);";
Solutions for LinqToDB:
MappingSchema.SetDataType(typeof(TimeSpan), DataType.NText);
Or:
MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
Example:
public class Program
{
private const string ConnectionString = "Data Source=:memory:;Version=3;New=True;";
public static void Main()
{
var dataProvider = new SQLiteDataProvider();
var connection = dataProvider.CreateConnection(ConnectionString);
connection.Open();
var dataConnection = new DataConnection(dataProvider, connection);
dataConnection.MappingSchema.SetDataType(typeof(TimeSpan), DataType.Int64);
dataConnection.CreateTable<Category>();
dataConnection.GetTable<Category>()
.DataContextInfo
.DataContext
.Insert(new Category
{
Id = 2,
Time = new TimeSpan(10, 0, 0)
});
foreach (var category in dataConnection.GetTable<Category>())
{
Console.WriteLine($#"Id: {category.Id}, Time: {category.Time}");
}
}
private class Category
{
public int Id { get; set; }
public TimeSpan Time { get; set; }
}
}

webservice DateTime unexpected value?

When I use the system.datetime as my datamember it returns a strange format in my datagridview.
My Datamembers looks like this:
[DataMember(Name = "TimeAdded")]
public DateTime TimeAdded;
And my AddStudent looks like this:
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
student.TimeAdded = DateTime.Now; // not important more so the method to get the correct format
students.Add(student);
}
The output I get is 2012-04-12T03:10:42.8138255+01:00 is there a way to fix this?
I think you want:
student.TimeAdded = DateTime.Now;
Right now you're just converting a null time to local time.
Assuming you are referring to the fact that your dates are set to default(DateTime), then you want yamen's answer, if you don't like the format the DateTime is showing, then add another property onto Student that uses a standard DateTime format string like so.
public class Student
{
// existing date, don't expose this
public DateTime TimeAdded;
// expose this instead
[DataMember(Name = "TimeAddedString")]
public string TimeAddedString
{
//show as "Monday, January 01, 0001 12:00 AM"
get { return this.TimeAdded.ToString("f"); }
}
}
public class Student
{
public string TimeAddedString
{
get
{
return this.TimeAdded.ToString("dd/MM/yyyy hh:mm:ss");
// your desired format can goes here
}
}
}
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
student.TimeAdded = DateTime.Now; // or your desired datetime
students.Add(student);
}
If you are converting incoming student time added you need to re-assign it:
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
student.TimeAdded = student.TimeAdded.ToLocalTime();
students.Add(student);
}

Better way to manage Session data

I need to persist in Session some data.
I wrote many properties like that:
public List<string> FillOrder
{
get { return Session[SessionKeys.QueryFillOrder] as List<string> ?? new List<string>(); }
set { Session[SessionKeys.QueryFillOrder] = value; }
}
When I have to consume this data I have to write code like that:
List<string> fillOrder = FillOrder;
fillOrder.Add(accordion.ID);
FillOrder = fillOrder;
that seems to me so ugly, because I would prefer to do that:
FillOrder.Add(accordion.ID);
but this way my value would not be saved back in Session.
Can you think of any better way to achieve the same result?
Thank you very much!
I always use a wrapper class around the ASP.NET session to simplify access to session variables:
public class MySession
{
// private constructor
private MySession()
{
FillOrder = new List<string>();
}
// Gets the current session.
public static MySession Current
{
get
{
var session = (MySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// **** add your session properties here, e.g like this:
public List<string> FillOrder {get; set; }
public string Property1 { get; set; }
public DateTime MyDate { get; set; }
public int LoginId { get; set; }
}
This class stores one instance of itself in the ASP.NET session and allows you to access your session properties in a type-safe way from any class, e.g like this:
MySession.Current.FillOrder.Add(accordion.ID);
int loginId = MySession.Current.LoginId;
string property1 = MySession.Current.Property1;
MySession.Current.Property1 = newValue;
DateTime myDate = MySession.Current.MyDate;
MySession.Current.MyDate = DateTime.Now;
This approach has several advantages:
you can initialize your session variables in the constructor (i.e. new List<string>)
it saves you from a lot of type-casting
you don't have to use hard-coded session keys throughout your application (e.g. Session["loginId"]
you can document your session items by adding XML doc comments on the properties of MySession
You can use an extension method as well, but I do think the example by M4N might be better:
EDIT made it a generic type
public static class Extensions
{
public static void AddWithSession<T>(this List<T> list, T value, string key)
{
list.Add(value);
HttpContext.Current.Session[key] = list;
}
}
str.AddWithSession(accordion.ID,SessionKeys.QueryFillOrder);
You could write an own class that implements ICollection or IList, there you would implement Add as Session[...] = ...
Using a single class for all Session variables as suggested by #M4N is a good idea, though it risks becoming a "God" class (in which case you could partition into several classes implemented in this way).
However you could just change your property implemetation as follows:
public List<string> FillOrder
{
get
{
List<string> result = Session[SessionKeys.QueryFillOrder] as List<string>;
if (result == null)
{
result = new List<string>();
Session[SessionKeys.QueryFillOrder] = result;
}
return result;
}
set { Session[SessionKeys.QueryFillOrder] = value; }
}
In this example, you probably don't want a setter.

Categories

Resources