// ==================== PROJECT STRUCTURE ====================
/*
Solution: ReflectionAssignment
├── MathsLib (Class Library)
├── AttributesLib (Class Library)
├── EntityLib (Class Library)
├── MathsConsole (Console Application)
└── ORMConsole (Console Application)
*/
// ==================== 1. MathsLib Class Library ====================
// File: MathsLib/Maths.cs
using System;
namespace MathsLib
{
public class Maths
{
public double Sum(double a, double b)
{
return a + b;
}
public double Subtract(double a, double b)
{
return a - b;
}
public double Multiply(double a, double b)
{
return a * b;
}
public double Divide(double a, double b)
{
if (b == 0)
throw new DivideByZeroException("Cannot divide by zero");
return a / b;
}
public void DisplayOperations()
{
Console.WriteLine("Available Operations:");
Console.WriteLine("1. Sum");
Console.WriteLine("2. Subtract");
Console.WriteLine("3. Multiply");
Console.WriteLine("4. Divide");
}
}
}
// ==================== 2. AttributesLib Class Library ====================
// File: AttributesLib/CustomAttributes.cs
using System;
namespace AttributesLib
{
// Custom attribute for marking classes as data tables
[AttributeUsage(AttributeTargets.Class)]
public class DataTableAttribute : Attribute
{
public string TableName { get; set; }
public DataTableAttribute(string tableName)
{
TableName = tableName;
}
}
// Custom attribute for marking properties as data columns
[AttributeUsage(AttributeTargets.Property)]
public class DataColumnAttribute : Attribute
{
public string ColumnName { get; set; }
public string DataType { get; set; }
public DataColumnAttribute(string columnName, string dataType = "")
{
ColumnName = columnName;
DataType = dataType;
}
}
// Custom attribute for marking properties as key columns (Primary Key)
[AttributeUsage(AttributeTargets.Property)]
public class KeyColumnAttribute : Attribute
{
public bool IsPrimaryKey { get; set; }
public KeyColumnAttribute(bool isPrimaryKey = true)
{
IsPrimaryKey = isPrimaryKey;
}
}
// Custom attribute for marking properties to be excluded from mapping
[AttributeUsage(AttributeTargets.Property)]
public class UnMappedAttribute : Attribute
{
}
}
// ==================== 3. EntityLib Class Library ====================
// File: EntityLib/Employee.cs
using System;
using AttributesLib;
namespace EntityLib
{
[Serializable]
[DataTable("Employees")]
public class Employee
{
[KeyColumn(true)]
[DataColumn("EmpNo", "INT")]
public int EmpNo { get; set; }
[DataColumn("Name", "VARCHAR(100)")]
public string Name { get; set; }
[DataColumn("Address", "VARCHAR(200)")]
public string Address { get; set; }
[DataColumn("Salary", "DECIMAL(10,2)")]
public decimal Salary { get; set; }
[UnMapped]
public decimal AnnualSalary
{
get { return Salary * 12; }
}
[DataColumn("Designation", "VARCHAR(50)")]
public string Designation { get; set; }
public Employee()
{
}
public Employee(int empNo, string name, string address, decimal salary, string designation)
{
EmpNo = empNo;
Name = name;
Address = address;
Salary = salary;
Designation = designation;
}
}
}
// File: EntityLib/Student.cs
using System;
using AttributesLib;
namespace EntityLib
{
[Serializable]
[DataTable("Students")]
public class Student
{
[KeyColumn(true)]
[DataColumn("RollNo", "INT")]
public int RollNo { get; set; }
[DataColumn("Name", "VARCHAR(100)")]
public string Name { get; set; }
[DataColumn("Address", "VARCHAR(200)")]
public string Address { get; set; }
[DataColumn("Course", "VARCHAR(50)")]
public string Course { get; set; }
public Student()
{
}
public Student(int rollNo, string name, string address, string course)
{
RollNo = rollNo;
Name = name;
Address = address;
Course = course;
}
}
}
// ==================== 4. MathsConsole Application ====================
// File: MathsConsole/Program.cs
using System;
using System.Reflection;
using System.IO;
namespace MathsConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Maths Library Reflection Demo ===\\n");
try
{
// Load the MathsLib assembly using reflection
string mathsLibPath = "MathsLib.dll";
Assembly mathsAssembly = Assembly.LoadFrom(mathsLibPath);
// Get the Maths class type
Type mathsType = mathsAssembly.GetType("MathsLib.Maths");
// Create an instance of Maths class
object mathsInstance = Activator.CreateInstance(mathsType);
char choice;
do
{
Console.WriteLine("\\n=== Math Operations Menu ===");
Console.WriteLine("1. Sum");
Console.WriteLine("2. Subtract");
Console.WriteLine("3. Multiply");
Console.WriteLine("4. Divide");
Console.WriteLine("5. Show Available Methods");
Console.WriteLine("6. Exit");
Console.Write("Enter your choice (1-6): ");
choice = Console.ReadKey().KeyChar;
Console.WriteLine();
if (choice >= '1' && choice <= '4')
{
Console.Write("Enter first number: ");
double num1 = Convert.ToDouble(Console.ReadLine());
Console.Write("Enter second number: ");
double num2 = Convert.ToDouble(Console.ReadLine());
string methodName = "";
switch (choice)
{
case '1': methodName = "Sum"; break;
case '2': methodName = "Subtract"; break;
case '3': methodName = "Multiply"; break;
case '4': methodName = "Divide"; break;
}
// Get the method using reflection
MethodInfo method = mathsType.GetMethod(methodName);
if (method != null)
{
try
{
// Invoke the method using reflection
object result = method.Invoke(mathsInstance, new object[] { num1, num2 });
Console.WriteLine($"Result: {num1} {GetOperatorSymbol(choice)} {num2} = {result}");
}
catch (TargetInvocationException ex)
{
Console.WriteLine($"Error: {ex.InnerException.Message}");
}
}
else
{
Console.WriteLine("Method not found!");
}
}
else if (choice == '5')
{
ShowAvailableMethods(mathsType);
}
else if (choice != '6')
{
Console.WriteLine("Invalid choice! Please try again.");
}
} while (choice != '6');
Console.WriteLine("Thank you for using Math Calculator!");
}
catch (FileNotFoundException)
{
Console.WriteLine("Error: MathsLib.dll not found. Please ensure the library is in the same directory.");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
static string GetOperatorSymbol(char choice)
{
return choice switch
{
'1' => "+",
'2' => "-",
'3' => "*",
'4' => "/",
_ => "?"
};
}
static void ShowAvailableMethods(Type mathsType)
{
Console.WriteLine("\\nAvailable Methods in Maths Class:");
MethodInfo[] methods = mathsType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (MethodInfo method in methods)
{
ParameterInfo[] parameters = method.GetParameters();
string paramStr = string.Join(", ", Array.ConvertAll(parameters, p => $"{p.ParameterType.Name} {p.Name}"));
Console.WriteLine($"- {method.ReturnType.Name} {method.Name}({paramStr})");
}
}
}
}
// ==================== 5. ORMConsole Application ====================
// File: ORMConsole/Program.cs
using System;
using System.Reflection;
using System.Linq;
using System.IO;
using System.Text;
using AttributesLib;
using EntityLib;
namespace ORMConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Basic ORM Using Reflection ===\\n");
try
{
// Test with Employee class
Console.WriteLine("1. Processing Employee Class:");
ProcessEntity(typeof(Employee));
Console.WriteLine("\\n" + new string('=', 50) + "\\n");
// Test with Student class
Console.WriteLine("2. Processing Student Class:");
ProcessEntity(typeof(Student));
// Create sample objects and generate SQL
Console.WriteLine("\\n" + new string('=', 50) + "\\n");
Console.WriteLine("3. Generating SQL for Sample Data:");
Employee emp = new Employee(101, "John Doe", "123 Main St", 50000, "Developer");
GenerateInsertSQL(emp);
Student student = new Student(1001, "Jane Smith", "456 Oak Ave", "Computer Science");
GenerateInsertSQL(student);
Console.WriteLine("\\n4. SQL Statements written to files:");
Console.WriteLine("- Employee_SQL.txt");
Console.WriteLine("- Student_SQL.txt");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
static void ProcessEntity(Type entityType)
{
Console.WriteLine($"Entity: {entityType.Name}");
// Check if class is marked as Serializable
bool isSerializable = entityType.IsSerializable;
Console.WriteLine($"Is Serializable: {isSerializable}");
if (!isSerializable)
{
Console.WriteLine("Class is not marked as Serializable. Skipping SQL generation.");
return;
}
// Get DataTable attribute
DataTableAttribute tableAttr = (DataTableAttribute)Attribute.GetCustomAttribute(entityType, typeof(DataTableAttribute));
string tableName = tableAttr?.TableName ?? entityType.Name;
Console.WriteLine($"Table Name: {tableName}");
// Get all properties
PropertyInfo[] properties = entityType.GetProperties();
Console.WriteLine($"\\nAll Properties ({properties.Length}):");
foreach (var prop in properties)
{
Console.WriteLine($"- {prop.PropertyType.Name} {prop.Name}");
}
// Remove unmapped properties
var mappedProperties = RemoveUnmappedFields(properties);
Console.WriteLine($"\\nMapped Properties ({mappedProperties.Length}):");
foreach (var prop in mappedProperties)
{
DataColumnAttribute colAttr = (DataColumnAttribute)Attribute.GetCustomAttribute(prop, typeof(DataColumnAttribute));
KeyColumnAttribute keyAttr = (KeyColumnAttribute)Attribute.GetCustomAttribute(prop, typeof(KeyColumnAttribute));
string columnName = colAttr?.ColumnName ?? prop.Name;
string dataType = colAttr?.DataType ?? "VARCHAR(50)";
bool isPrimaryKey = keyAttr?.IsPrimaryKey ?? false;
Console.WriteLine($"- {columnName} ({dataType}){(isPrimaryKey ? " [PRIMARY KEY]" : "")}");
}
// Generate CREATE TABLE SQL
string createTableSQL = GenerateCreateTableSQL(entityType, tableName, mappedProperties);
Console.WriteLine($"\\nGenerated CREATE TABLE SQL:");
Console.WriteLine(createTableSQL);
}
static PropertyInfo[] RemoveUnmappedFields(PropertyInfo[] properties)
{
return properties.Where(prop =>
Attribute.GetCustomAttribute(prop, typeof(UnMappedAttribute)) == null
).ToArray();
}
static string GenerateCreateTableSQL(Type entityType, string tableName, PropertyInfo[] properties)
{
StringBuilder sql = new StringBuilder();
sql.AppendLine($"CREATE TABLE {tableName} (");
string[] columnDefinitions = new string[properties.Length];
string primaryKeyColumn = "";
for (int i = 0; i < properties.Length; i++)
{
var prop = properties[i];
DataColumnAttribute colAttr = (DataColumnAttribute)Attribute.GetCustomAttribute(prop, typeof(DataColumnAttribute));
KeyColumnAttribute keyAttr = (KeyColumnAttribute)Attribute.GetCustomAttribute(prop, typeof(KeyColumnAttribute));
string columnName = colAttr?.ColumnName ?? prop.Name;
string dataType = colAttr?.DataType ?? GetDefaultDataType(prop.PropertyType);
bool isPrimaryKey = keyAttr?.IsPrimaryKey ?? false;
if (isPrimaryKey)
{
primaryKeyColumn = columnName;
columnDefinitions[i] = $" {columnName} {dataType} NOT NULL";
}
else
{
columnDefinitions[i] = $" {columnName} {dataType}";
}
}
sql.AppendLine(string.Join(",\\n", columnDefinitions));
if (!string.IsNullOrEmpty(primaryKeyColumn))
{
sql.AppendLine($", PRIMARY KEY ({primaryKeyColumn})");
}
sql.AppendLine(");");
return sql.ToString();
}
static string GetDefaultDataType(Type type)
{
return type.Name switch
{
"Int32" => "INT",
"String" => "VARCHAR(100)",
"Decimal" => "DECIMAL(10,2)",
"DateTime" => "DATETIME",
"Boolean" => "BIT",
_ => "VARCHAR(50)"
};
}
static void GenerateInsertSQL(object entity)
{
Type entityType = entity.GetType();
// Check if serializable
if (!entityType.IsSerializable)
{
Console.WriteLine($"Entity {entityType.Name} is not serializable. Skipping INSERT SQL generation.");
return;
}
DataTableAttribute tableAttr = (DataTableAttribute)Attribute.GetCustomAttribute(entityType, typeof(DataTableAttribute));
string tableName = tableAttr?.TableName ?? entityType.Name;
PropertyInfo[] properties = entityType.GetProperties();
PropertyInfo[] mappedProperties = RemoveUnmappedFields(properties);
StringBuilder sql = new StringBuilder();
StringBuilder columns = new StringBuilder();
StringBuilder values = new StringBuilder();
sql.AppendLine($"INSERT INTO {tableName} (");
for (int i = 0; i < mappedProperties.Length; i++)
{
var prop = mappedProperties[i];
DataColumnAttribute colAttr = (DataColumnAttribute)Attribute.GetCustomAttribute(prop, typeof(DataColumnAttribute));
string columnName = colAttr?.ColumnName ?? prop.Name;
if (i > 0)
{
columns.Append(", ");
values.Append(", ");
}
columns.Append(columnName);
object value = prop.GetValue(entity);
if (value == null)
{
values.Append("NULL");
}
else if (prop.PropertyType == typeof(string))
{
values.Append($"'{value.ToString().Replace("'", "''")}'");
}
else
{
values.Append(value.ToString());
}
}
sql.AppendLine($" {columns}");
sql.AppendLine(") VALUES (");
sql.AppendLine($" {values}");
sql.AppendLine(");");
Console.WriteLine($"\\nINSERT SQL for {entityType.Name}:");
Console.WriteLine(sql.ToString());
// Write to file
string fileName = $"{entityType.Name}_SQL.txt";
File.WriteAllText(fileName, sql.ToString());
Console.WriteLine($"SQL written to: {fileName}");
}
}
}
// ==================== Compilation Instructions ====================
/*
To compile and run this solution:
1. Create MathsLib.dll:
csc /target:library /out:MathsLib.dll MathsLib/Maths.cs
2. Create AttributesLib.dll:
csc /target:library /out:AttributesLib.dll AttributesLib/CustomAttributes.cs
3. Create EntityLib.dll:
csc /target:library /reference:AttributesLib.dll /out:EntityLib.dll EntityLib/Employee.cs EntityLib/Student.cs
4. Compile MathsConsole:
csc /reference:MathsLib.dll MathsConsole/Program.cs
5. Compile ORMConsole:
csc /reference:AttributesLib.dll;EntityLib.dll ORMConsole/Program.cs
Run the applications:
- MathsConsole.exe (for Part A)
- ORMConsole.exe (for Part B)
*/