Archive for the ‘General’ Category
Convert ILIST, LIST to DataSet with child tables and relations
There was requirement to convert ILIST or LIST to DataSet so that it can be assigned to some of the controls like Grid or DevExpress Grid. For that i have written following class to convert from LIST or ILIST to DataSet
- Converts only ILIST and LIST
- Convert sub lists to another table which will be related to the parent list
- Creates Relation between tables
- Works only on the properties not on fields. You can easily modify it for that
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
namespace TowardsNext
{
public static class ListConvertor
{
public static DataSet ConvertToDataSet<T>(IList list)
{
DataSet dataSet = new DataSet();
CreateDataSet(dataSet, typeof(T), false);
FillDataSet(typeof(T), list.ToList(), dataSet, -1);
CreateRelations(dataSet, typeof(T), null);
return dataSet;
}
///
/// Create the structure for all the tables in the data set
///
/// Data set in which tables will be created
/// Type of which dataset has to be created
/// Whether current type is a child table
private static void CreateDataSet(DataSet dataSet, Type type, bool isChildTable)
{
DataTable dataTable = new DataTable(type.Name);
//Create the ID columns for having relation in the tables
dataTable.Columns.Add(new DataColumn("ID", typeof(int)));
if (isChildTable)
{
dataTable.Columns.Add(new DataColumn("ParentID", typeof(int)));
}
// Create the structure for the data tables to be
// added in the the data set
foreach (PropertyInfo pInfo in type.GetProperties())
{
if (pInfo.PropertyType.IsGenericType &&
(pInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
|| pInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
// If associate lists are there make then another table
CreateDataSet(dataSet,
pInfo.PropertyType.GetGenericArguments()[0],
true);
}
else
{
dataTable.Columns.Add(new DataColumn(pInfo.Name, pInfo.PropertyType));
}
}
//Add the table to the dataset
dataSet.Tables.Add(dataTable);
}
///
/// Fill all the tables of data set with data in the respective list
///
/// Type of which datatable is to be filled
/// List of data
/// Data Set in which data tables will be filled with data
/// ID of parent record. If -1 one then no parent
private static void FillDataSet(Type type, IList list, DataSet dataSet, int parentID)
{
PropertyInfo[] propertyInfos = type.GetProperties();
DataTable dataTable = dataSet.Tables[type.Name];
int id = dataTable.Rows.Count + 1;
foreach (object item in list)
{
DataRow row = dataTable.NewRow();
// Set new id and related parent id
row["ID"] = id;
if (parentID != -1)
row["ParentID"] = parentID;
// Load all the data from the properties of the type
// and save them into the datatable
foreach (PropertyInfo info in propertyInfos)
{
if (info.PropertyType.IsGenericType &&
(info.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
|| info.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
IList subList = (IList)info.GetValue(item, null);
if (subList != null && subList.Count > 0)
{
FillDataSet(subList[0].GetType(),
subList,
dataSet, id);
}
}
else
{
row[info.Name] = info.GetValue(item, null);
}
}
dataTable.Rows.Add(row);
id++;
}
}
///
/// Creates the relation between the tables according to the
/// type and parent table on field ID and ParentID
///
/// Data set containing parent and child table
/// Type of the list
/// Parent table to which relations has to be done
private static void CreateRelations(DataSet dataSet, Type type, DataTable parentTable)
{
DataTable dataTable = dataSet.Tables[type.Name];
// If parent table exsits then create relation
// with child table on field Parent ID
if (parentTable != null)
{
dataSet.Relations.Add(
new DataRelation(parentTable.TableName + "_ID_"
+ "PARENTID_" + dataTable.TableName,
parentTable.Columns["ID"],
dataTable.Columns["ParentID"]));
}
// Check for other lists under current object
// go for another relation if exists
foreach (PropertyInfo pInfo in type.GetProperties())
{
if (pInfo.PropertyType.IsGenericType &&
(pInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
|| pInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
// If associate lists are there make then another table
CreateRelations(dataSet,
pInfo.PropertyType.GetGenericArguments()[0],
dataTable);
}
}
}
}
}
Tested with following code
;public class Student
{
public string Name { get; set; }
public string Class { get; set; }
}
public class Teacher
{
public string Name { get; set; }
public string Address { get; set; }
public List<Student> Students { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student { Name = "Ram Prasad", Class = "LKG" });
students.Add(new Student { Name = "Dina Nath", Class = "Prep" });
List<Teacher> teachers = new List<Teacher>();
teachers.Add(
new Teacher{
Name="Om Prakash",
Address="Mangalore",
Students = students
});
teachers.Add(new Teacher
{
Name = "Om Prakash 2",
Address = "Gurgaon",
Students = students
});
DataSet dataSet = ListConvertor.ConvertToDataSet<Teacher>(teachers);
}
}
It is not tested in all the cases and condition only checked with few cases and requirement. If any problem do reply, i will fix it up and re-post it. After converting we assigned it to devexpress grid and get the following successful output
Named & Optional Parameter, C# 4.0 Part 2
In visual basic we were having optional parameter option which can help you to send only some parameter to methods and reset will take the default values. Same feature is part of C# 4.0 where you can have default values for the parameters.
But one more noticeable feature is “named parameter”. You might have seen in VB also that if you want to set any of the parameter no values then you have to leave all other parameters also which are defined after that variable. To sort this out you can use named parameter which specify the name of the parameter and value for it “seats:4” where seats is the parameter and 4 is the value.
Both of the features are shown below in sample
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ParameterFeatures
{
class Program
{
static void Main(string[] args)
{
Vehicle car = new Vehicle("V6");
Vehicle van = new Vehicle(seats:4);
Console.WriteLine("Engine : " + car.Engine);
Console.WriteLine("Seats : " + van.Seats.ToString());
Console.ReadLine();
}
}
class Vehicle
{
public string Engine { get; set; }
public int Seats { get; set; }
public Vehicle(string engine = "V8", int seats = 5)
{
Engine = engine;
Seats = seats;
}
}
}
Dynamic Lookup & dynamic Type, C# 4.0 Part 1
C# 4.0 is out once again with new set of features. Now we will see one of the new feature of it, which is know as Dynamic Lookup. It is new approach for invoking thing more dynamically than before. It gives big freedom and working with various different kind of objects like COM etc will be too easy.
Big question how. I have written one sample below where i am grabbing the object of excel instance which is already running and filling data in it. In the previous version of C# we used to do it with the help of InvokeMember funtions of the object. But in C# 4.0 story is differentM
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DynamicObjects
{
class Program
{
static void Main(string[] args)
{
dynamic excel = System.Runtime.
InteropServices.Marshal.GetActiveObject("Excel.Application");
//Display the name of the work book
Console.WriteLine(excel.ActiveWorkbook.Name);
//Select the range and place some data here
excel.Range("B2").Select();
excel.ActiveCell.FormulaR1C1 = "Sample Data";
//Wait for the input
Console.ReadLine();
}
}
}
It was so simple to use the dynamic object, That i have to just type out the properties and method in the front of dynamic object. At the time of getting that object it will be handled automatically and will map the functions and methods. Its really a great feature, which can save time and give more freedom to the developer.
Difference between VAR & DYNAMIC
VAR It is also know as local type inference feature of C#. This feature will allow you to remove the data type from the left hand side and create the type on the fly. But still you have to specify the type in the right hand side and var will be replaced by the new type which will be built at compile time.
DYNAMIC it is step ahead of the VAR. It will get the information of the object not at the compile time rather at the time of creation of that object. It is done at runtime only.
XML Serialization
Some time we need to save the data in the files which is nothing but the details of the object. For example i am having a application doing vector drawing and i want to save the details of the line object not the image file. How to save the line object and how to get it back. We can use serialization with which we can save our object in file directly and can load it too. Also we can use XML Serialization which is so popular these days.
We have to just mark out objects and class with certain Attributes like XMLRoot, XMLElement, XMLAttribute and so on.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace XMLSerialization
{
static class Program
{
static void Main()
{
DoSerialization();
}
private static void DoSerialization()
{
Student student1 = new Student { Name = "A", Marks = 23 };
Student student2 = new Student { Name = "B", Marks = 25 };
Students students = new Students();
students.StudentList.Add(student1);
students.StudentList.Add(student2);
XmlSerializer xmlSerialize = new XmlSerializer(students.GetType());
StreamWriter writer = new StreamWriter("a.xml");
xmlSerialize.Serialize(writer, students);
writer.Close();
StreamReader reader = new StreamReader("a.xml");
Students studentsfromFile = (Students)xmlSerialize.Deserialize(reader);
foreach (Student st in studentsfromFile.StudentList)
{
Console.WriteLine("Name : {0} Marks : {1}", st.Name, st.Marks);
}
Console.ReadLine();
}
}
[XmlRoot("Students")]
public class Students
{
[XmlElement("Student")]
public List<Student> StudentList = new List<Student>();
}
public class Student
{
[XmlElement("Name")]
public string Name;
[XmlElement("Marks")]
public int Marks;
}
}
Generics with simple example
Generics are the feature supported from the version 2.0 of .Net framework. Why it is required and where it is used. Consider a case in which you are creating a collection of objects now those objects can be int or string or anything. Now how we will design the class since we are not aware of the type used by the developer. In this case we can make of use of Generics where the type of the object will be specified only at the initialization or declaration of the collection class. Here we have to use generic type parameter T.
public class GCollection
{
private List _list = new List();
public void Add(T item)
{
_list.Add(item);
}
public T GetItem(int index)
{
return _list[index];
}
}
See the following image to get an idea how it works
Save Settings/Data in IsolatedStorage C#
IsolatedStorage is a storage isolated from users and assemblies. Application has to just tell the name of the file and location of the file will be handled by .net. This storage is safe has compared to keeping file in the application path and saving settings in it. Developer can save the settings of the application in the isolatedstorage in a file. Which he can recover easily. Isolated Storage is a kind of a virtual folder only. These file can have scope for user, domain, application, machine and more.
Check out the following sample
class Program
{
static void Main(string[] args)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetStore(
IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
CreateFile("settings", storage);
Console.WriteLine("File Contents : \n" + ReadFile("settings", storage));
GetStoreInformation(storage);
storage.Close();
storage.Dispose();
Console.ReadLine();
}
public static void CreateFile(string fileName, IsolatedStorageFile storage)
{
IsolatedStorageFileStream stream =
new IsolatedStorageFileStream(fileName,
System.IO.FileMode.Create, storage);
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine("Sample text");
writer.WriteLine("Isolated Storage");
writer.Close();
stream.Close();
}
public static string ReadFile(string fileName, IsolatedStorageFile storage)
{
IsolatedStorageFileStream stream =
new IsolatedStorageFileStream(fileName,
System.IO.FileMode.Open, storage);
StreamReader reader = new StreamReader(stream);
string data = reader.ReadToEnd();
reader.Close();
stream.Close();
return data;
}
public static void GetStoreInformation(IsolatedStorageFile storage)
{
string[] dirs = storage.GetDirectoryNames("*");
string[] files = storage.GetFileNames("*");
Console.WriteLine("Files");
foreach (string filename in files)
{
Console.WriteLine(" |- " + filename);
}
Console.WriteLine("\nDirectories" );
foreach (string dir in dirs)
{
Console.WriteLine(" |- " + dir);
}
}
}
Replace data in file C#
There was one of the requirement to find and replace the data from the file. First we have written code to load all the data in the variable and then replace it. But it will be a problem with a huge files. So we wrote two methods to replace it line by line or chunk by chunk. Both of these methods are written below. These methods although seems correct to us but not tested. If any problem do reply back so that it can be modified
Download sample from FileFindReplace Sample
public class FileFindRelpace
{
///
/// Replace the data in the Huge files searching and replacing chunk
/// by chunk. It will create new file as filepath + ".tmp" file with
/// replaced data
///
/// Path of the file
/// Text to be replaced
/// Text with which it is replaced
public void ReplaceLineByLine(string filePath, string replaceText, string withText)
{
StreamReader streamReader = new StreamReader(filePath);
StreamWriter streamWriter = new StreamWriter(filePath + ".tmp");
while (!streamReader.EndOfStream)
{
string data = streamReader.ReadLine();
data = data.Replace(replaceText, withText);
streamWriter.WriteLine(data);
}
streamReader.Close();
streamWriter.Close();
}
///
/// Replace the data in the Huge files searching and replacing chunk
/// by chunk. It will create new file as filepath + ".tmp" file with
/// replaced data
///
/// Path of the file
/// Text to be replaced
/// Text with which it is replaced
/// Length of the data to be loaded at one go
public void ReplaceByChunk(string filePath, string replaceText, string withText, int chunkLength)
{
int loadLength = chunkLength + replaceText.Length;
char[] buffer = new char[loadLength];
int index = 0;
int replaceLength = replaceText.Length;
StreamReader streamReader = new StreamReader(filePath);
StreamWriter streamWriter = new StreamWriter(filePath + ".tmp");
//Load the data according to the chunk length specified
//also load the extra data according to the length of
//the replace text so that chunk end and start text break
//can be handled
while(true)
{
//Seek to the position from where we want to start and
//load the data in to the memory
streamReader.DiscardBufferedData();
streamReader.BaseStream.Seek(index, SeekOrigin.Begin);
int count = streamReader.ReadBlock(buffer,0,loadLength);
if (count == 0) break;
//Get the data and check whether the extra loaded data
//is replaceable if yes then set end replaced flag
string data = ConvertToString(buffer, count);
bool isEndReplaced = false;
if(count >= chunkLength)
isEndReplaced = (data.LastIndexOf(withText, chunkLength) > 0);
//Replace the data with the specified data and save the
//new data in the new file
data = data.Replace(replaceText, withText);
if(isEndReplaced)
{
streamWriter.Write(data);
index += count;
}
else
{
if (count >= chunkLength)
{
streamWriter.Write(data.Substring(0, data.Length - replaceLength));
index += chunkLength;
}
else
{
streamWriter.Write(data);
index += chunkLength;
}
}
}
streamReader.Close();
streamWriter.Close();
}
private string ConvertToString(char[] buffer, int count)
{
StringBuilder data = new StringBuilder(buffer.Length);
for (int i = 0; i < count; i++)
{
data.Append(buffer[i]);
}
return data.ToString();
}
}
Handling services with the help of ServiceController from your application
You may need to get the information regarding service or need to start or stop it. Doing it from the C# is very easy with the help of ServiceController. Just create the object of the servicecontroller with the specified service and you can control that service with the help of that object
ServiceController serviceController = new ServiceController("servicename");
//Start it now
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running);
//Stop it now
serviceController.Stop();
serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
Also you can get verious other information from this object like status, display name, dependencies and so on.
Implicit Operator Overloading
We can assign values to the int, double, float, string data types directry by writing (int l = 0) and even we can do the same to String data type which is a reference type not the value type. How to implement this method to our reference data type. Solution for this kind of requirement is Implicit operator overloading. Now let us see how it works
public class Amount { double _value; /// /// Gets or sets the Amount value. /// public double Value { get { return _value; } set { _value = value; } } public Amount(double value) { _value = value; } public override string ToString() { return string.Format("{0}", Value); } /// /// Set the amount value on the basis of the double value sent /// /// Amount in double data type. /// Implicitly created instance. public static implicit operator Amount(double amount) { Amount amt = new Amount(amount); return amt; } /// /// Get/Return the value set to the instance of the amount class /// /// Amount Instance /// Amount value in double public static implicit operator double(Amount amount) { return amount.Value; } }
We were in need to new kind of data type which is specially required for our required. We designed a class name as Amount. But problem was of assigning the values. All the time we have to use new keyword. So we implimented this implicit overloading and we got a new data type for our self. Also we can add more functions to it
Truncating the path (Path with with ellipses)
While showing the file path in the menus/status bar/caption bar we face difficulty with long paths. Since it will increase the width/length too much and it will become odd. We can cut short that path with the help of the following function and we will utilise those path where ever we want to show with ellipses format. Now here in this particular function it is done to very simple extent. You need to pass the path it will take out the drive or base folder and append one directory name to it. Later it will add the file name to this path with ellipses ‘…’.
public string GetEllipsesPath(string fullPath)
{
string ellipsesPath = "";
if (!string.IsNullOrEmpty(fullPath))
{
string[] dirName = fullPath.Split('\\');
string fileName = Path.GetFileName(fullPath);
//Shorten the file name················
if (fileName.Length > 25)
{
fileName = fileName.Substring(0, 15) + "..."
+ fileName.Substring(fileName.Length - 5, 5);
}
//Shortten the complete path
ellipsesPath = Path.GetPathRoot(fullPath) + (dirName.Length > 2 ? dirName[1]
+ @"\..\" : "") + fileName;
}
return ellipsesPath;
}
This function can further be modified having another parameter named ‘length’. with that we can give developer option of having the of the specified size. You can also use the api function to perform the same function .
[DllImport("shlwapi.dll")] private static extern bool PathCompactPathEx(string pszOut, string szPath, int cchMax, int dwFlags);



