Since others have covered the basics I would add it's best to use strong type parameters rather than a base object. Then using a plain object you would then need to first check it's underlying type then cast it.
Below is the tip of the iceberg.
Example, I want a list of employees and managers in a list.
We start off with a base class person
public class Person : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime HireDate { get; set; }
public string FullName => $"{FirstName} {LastName}";
public override string ToString() => $"{Id} {FullName}";
}
Employee class which inherits Person
public class Employee : Person
{
public int ReportsTo { get; set; }
}
Mock them up into a single list
public class Mocked
{
public static List<Person> PeopleList()
{
var employees = new List<Employee>()
{
new() {Id = 1, FirstName = "Joe", LastName = "Jones", HireDate = new DateTime(2018,12,1), ReportsTo = 5},
new() {Id = 2, FirstName = "Mary", LastName = "Smith", HireDate = new DateTime(2018,9,1), ReportsTo = 5},
new() {Id = 3, FirstName = "Nancy", LastName = "Ravioli", HireDate = new DateTime(2017,4,12), ReportsTo = 6},
new() {Id = 4, FirstName = "Andrew", LastName = "Fuller", HireDate = new DateTime(2019,7,2), ReportsTo = 6},
new() {Id = 7, FirstName = "Steven", LastName = "Buchanan", HireDate = new DateTime(2015,5,16), ReportsTo = 5},
new() {Id = 9, FirstName = "Karen", LastName = "Stone", HireDate = new DateTime(2020,5,16), ReportsTo = 8}
};
var people = new List<Person>()
{
new Manager() {Id = 5, FirstName = "Anne", LastName = "Wordsworth",
HireDate = new DateTime(2015,7,2), YearsAsManager = 3,Employees = employees.Take(2).ToList()},
new Manager() {Id = 6, FirstName = "Bob", LastName = "Gallagher",
HireDate = new DateTime(2014,7,2), YearsAsManager = 4,Employees = employees.Skip(2).Take(2).ToList()},
new Manager() {Id = 8, FirstName = "Michael", LastName = "Suyama",
HireDate = new DateTime(2014,7,2), YearsAsManager = 1,Employees = employees.Skip(employees.Count -1).Take(1).ToList()}
};
people.AddRange(employees);
return people;
}
}
Then say in a form declare a list of Person
private readonly List<Person> _peopleList;
In form load event load the list using the mocked data above.
_peopleList = Mocked.PeopleList();
Then check types
foreach (Person person1 in _peopleList)
{
if (person1 is Manager person)
{
_stringBuilder.AppendLine(person.FullName);
}
}
Other ideas, use generics e.g.
namespace ExtensionsLibrary
{
public static class GenericExtensions
{
public static bool IsPositive<T>(this T value) where T : struct, IComparable<T> =>
value.CompareTo(default(T)) > 0;
}
}
Usage on int a and decimal
decimal someDecimal = 1.4m;
int someInt = 3;
if (someDecimal.IsPositive())
{
}
if (someInt.IsPositive())
{
}
Then if all elements are the same why use object e.g. (where sampleArray might be passed as a parameter)
Type type = typeof(string);
object[] sampleArray = { "Hello", "C#" };
var destinationArray = Array.CreateInstance(type, sampleArray.Length);
Array.Copy(sampleArray, destinationArray, sampleArray.Length);
Look at param arrays.
Then finally pattern matching
foreach (var o in sampleArray)
{
switch (o)
{
case string s:
Console.WriteLine($"o is a string with value of {s}");
break;
case int i:
Console.WriteLine($"o is a int with value of {i}");
break;
case bool b:
Console.WriteLine($"Bool {b}");
break;
}
}