passing different objects of same base class to method - c#

Basically, I would like to create a Method, that takes a base-class as a parameter, and can be used "generic" for derived classes
ef-code-first classes:
the base class
public abstract class BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
}
derived classes:
public class DerivedA:BaseClass
{
public string AValue {get;set;}
...more specific fields
}
public class DerivedB:BaseClass
{
public string BValue {get;set;}
..... more specific fields
}
I call a "generic Method" with these slightly different objects:
System.Data.Entity.DbSet<DerivedA> _dA....
System.Data.Entity.DbSet<DerivedB> _dB....
genericMethod(_dA.Where(a => a.Name.StartsWith("a name")))); //<-contains records
genericMethod(_dB.Where(a => a.Id==5)); //<---- contains records
Both "Where..." contain records in debug (after clicking on Enumerate)
now the method:
public string genericMethod(<IQueryable>BaseClass _myClass)
{
foreach (BaseClass c in _myClass) // <-------class is empty - no records
{
// do something usefull...
}
return someResult
}
But no records are contained, when inside the method.
Is it possible, what I am trying to do...?
Does it make sense?
There are no design-time or compile-time or runtime errors, but the passed object contains no records when passed to the method, but it contained records in the calling statement.
What did I do wrong?
Is there a better approach? -
I need this Method, for manipulation of more than two (maybe ten) derived classes, and therefor I want it "generic".
Thank you!

When faced with something like this, I like to simplify my code.
I would try removing the _dA.Where(a => a.Name.StartsWith("a name")) and _dB.Where(a => a.Id==5) from the method call and put them into variables first (and then pass the variable into the method).
This will allow you to better inspect your code and perhaps shed light on the problem.

add .ToList() to materialize the query before you pass it to the method:
genericMethod(_dA.Where(a => a.Name.StartsWith("a name"))).ToList());
Otherwise you're not really passing the result of the query, you're just passing a query that needs to be evaluated first. ToList() will evaluate it for you. When you look in the debugger watch, it's basically evaluating it for you on the fly, that's why you see rows returned.
After that, change your method to deal with IList instead of IQueryable.

Related

How to sort a List<> that contains derived class objects, by derived class method

I have a double problem here. I need to sort a List<> that I know contains objects of a derived class to the class that the list was declared to contain originally. AND, I need to sort by the return value from a method in that derived class, which takes a parameter. Keep in mind that I already know the List contains objects all of the derived class type.
I've created some sample code here to demonstrate the question since the real code cannot be shared publicly. Note, I have no control over the base conditions here (i.e. the fact that the List<> collection's declared contents are the parent class and that it contains objects of the derived class, which contains a method that takes an argument and returns the values that I need to sort the collection by). So, I doubt I'd be able to use any suggestion that requires changes there. What I think I need is a way to specify (cast?) what is really in the List so I can access the method defined there. But I'm open to other thoughts for sure. Otherwise I'm left with a traditional bubble sort. Thanks.
public class Component
{
public int X;
public int Y;
}
public class ComponentList : List<Component>
{
// Other members that deal with Components, generically
}
public class Fence : Component
{
public int Distance(int FromX, int FromY)
{
int returnValue = 0;
// Caluclate distance...
return returnValue;
}
}
public class Yard : Component
{
// Yada yada yada
}
public class MyCode
{
public List<Component> MyFences;
public MyCode(List<Component> Fences, int FromX, int FromY)
{
// Sort the fences by their distance from specified X,Y
Fences.Sort((A as Fence, B as Fence) => A.Distance(FromX, FromY).CompareTo(B.Distance(FromX, FromY)));
// Or
List<Fence> sortedFences = MyFences.OrderBy(A => A.Distance(FromX, FromY)).ToList();
// Or ???
}
}
Use the Enumerable.Cast<Fence> extension method to transform your IEnumerable<Component> to IEnumerable<Fence>. Then I'd use your second approach (the OrderBy approach) to sort it, but that's my preference.
List<Fence> sortedFences = MyFences.Cast<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
This approach will throw if there is an object in MyFences that can't be cast to Fence. If you expect that the code should only be passed Fences, this might be what you want. If, instead, you want to skip over non-Fence members, you can use:
List<Fence> sortedFences = MyFences.OfType<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();

Creating a Many to One Class Relationship

I have a set of class objects that I can not touch. All of them have an ID property that I would like to access in other functions in a generic way.
For simplicities sake here is an example of my problem.
class Example1 {
int ID { get; set;}
}
class Example2 {
int ID { get; set; }
}
I am not able to edit either of these two classes or the library they are in.
I also have a function that expects an ID that can come from either Example1 or Example2. In order to handle this I have come up with a number of solutions but am curious what the proper way to solve this would be.
I could:
Use dynamic classes to access the various classes ID's.
Use reflection to pull out an ID parameter from any given type.
Use an odd inheritance by creating a new class so that Example1ViewModel : Example1, IIdentifiableObject and then expect IIdentifiableObject in my function and implement a copy constructor in Example1ViewModel to handle collecting the data
Write a separate filter function that can extract out the relevant parts from either class and provide the results.
None of these solutions seem particularly good to me. How should I be handling a many to one relationship like this in code and are there tools that C# provides to handle this?
possible solution using extension methods for the classes
public static class MyExtensions
{
public static int GetId(this Example1 ex)
{
return ex.Id;
}
public static int GetId(this Example2 ex)
{
return ex.Id;
}
}
You can add a static method using reflection:
public static int GetId(object obj)
{
Type type = obj.GetType();
return Convert.ToInt32(type.GetProperty("ID").GetValue(obj, null));
}
Then you can invoke it with any object to get the id property value.
Here is the solution that we ended up using and why.
We are using an inheritence structure that that takes the following two base classes:
FooExample
BarExample
and wraps them in the following
IExample
FooExampleModel : IExample
BarExampleModel : IExample
Both FooExampleModel and BarExampleModel have constructors which accept the class they are wrapping.
The importance of this is that it allows us to create methods accepting IExample instances without having to manipulate data beforehand. Additionally, unlike using dynamic types or reflection this solution provides us with compile time error checking.
Unfortunately using extension methods does not work. While it allows us to call the same method on two different object types like we wanted it does not allow those objects to be passed as Generic types to a seperate function.
The result of all of this is that this is now possible:
var foos = new List<FooExample>(); //Pretend there is data here
var bars = new List<BarExample>();
var examples = foos.Select((foo) => (IExample)new FooExampleModel(foo))
.Concat(bars.Select((bar) => (IExample)new BarExampleModel(bar)))
.ToList(); // Force evaluation before function call
DoSomethingOnIExamples(examples);
Besides that slightly gross LINQ query this appears to be the best way to accomplish this (DoSomethingOnIExamples(...) is a function accepting an IEnumerable<IExample> argument). Obviously this solution gets less nice as more types are added to this mix.

Taking an object and adding it to the appropritae collection

I am doing a few labs and it has me creating multiple classes that are inheriting from a base class. i have created the base class, a student class that inherits from the base class, which creates a student and a teacher class that inherits from the base class, which creates a teacher. Now i am working on creating a school class that does not inherit any class. i have done most of what it is wanting me to do, but i am stuck on creating the appropriate methods to add the objects to its appropriate classes. I need assistance and guidance on how to create these methods so i may proceed. I am just going to post the Student class that i am working in right now and the instructions. I am not looking for someone to do my homework for me, i just cant seem to find anything online that can guide me in the right directions. thank you for your help.
Methods
Add(base) - Takes a teacher/student object and adds it to the
appropriate collection.
Print(base[]) - Private method that takes an
array of your base class object and prints all the elements of the
array.
3 Print(bool students = true) - Public method that prints out the
list of students, or list of teachers based upon the parameter value.
This is done by calling the Print(base[]) with the student[] or
teacher[] based upon the bool.
namespace BaseClass
{
class School
{
List<Teacher> staff = new List<Teacher>();
List<Student> students = new List<Student>();
public Student Students
{
get
{
students.Count();
return Students;
}
}
public Teacher Staff
{
get
{
if(Staff.EnumProp == Status.Employeed)
{
staff.Count();
}
return Staff;
}
}
public void Add(Teacher t1, Student s1) //not sure if this is correct or
//what to do in this method??
{
staff.Add(t1);
students.Add(s1);
//i also need help in the following methods. i am not sure what needs to be put
//in the parameter of the method, based on the instructions.
Based on requirement 1, you'd have to Add(Base c) and determine the collection to add to from there. e.g. (c is Teacher ? staff : students).Add(c). Normally such a class would have overloads (Add(Teacher) and Add(Student)) separately as well to be able to add directly.
public void Add(Base c)
{
if(c is Teacher)
staff.Add((Teacher)c);
else
students.Add((Student)c);
}
2 depends on the output type. With assignments outputting to the console is often enough, so you can use something like
void Print(params Base[] peeps)
{
foreach(var c in peeps)
c.Print();
}
No matter how Print is implemented, step 3 is actually very easy. You can just call your Print(Base[]) as stated in the requirements. To get that array, you have to determine which collection to use, just as in req. 1. (it does sound like 2 separate collections are wanted, otherwise a single collection could be used where Base exposes the role of the person).
public void Print(bool students = true)
{
if(students)
Print(this.students.ToArray());
else
Print(staff.ToArray());
}
PS, as mentioned in the comments the Students and Staff properties seem to expose some behavior that could be changed, but since that outside the scope of the question, won't go there unless you want us to ;)
Add(base) - Takes a teacher/student object and adds it to the appropriate collection.
For adding you can have two methods with same name but different signature. they are called method overloads. Compiler can distinguish between them by looking at the parameters they take.
These methods are both defined in base method. but better design would be to put each method in its appropriate class. (i.e Teacher and Student class)
public void Add(Teacher teacher)
{
staff.Add(teacher);
}
public void Add(Student student)
{
students.Add(student);
}
Print(base[]) - Private method that takes an array of your base class object and prints all the elements of the array.
If i understood correctly you want to print all elements of student or teacher. thats all?
In your base class you can have private method that prints array.
private void Print(Base[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i].ToString());
}
}
It is better to override ToString method for both Student and Teacher class. for example this method is required in both classes.
public override string ToString() // write this method in both student and teacher classes.
{
return string.Format("Name : {0} , Age : {1}",studentName,studentAge ); // return optional information of student instance.
}
3 Print(bool students = true) - Public method that prints out the list of students, or list of teachers based upon the parameter value. This is done by calling the Print(base[]) with the student[] or teacher[] based upon the bool.
You just need a simple check.
public void Print(bool students = true)
{
if(students)
Print(Students.ToArray());
else
Print(Staff.ToArray());
}
This only works if its inside Base class behind Print(base[]). Otherwise Print(base[]) have to be protected.
A better design would be to add each print method in child classes separately.
In your get and set method what you are doing is really useless.
Count() is a linq method that counts and gives you the length of list. you can use the property of list itself. Count(without parenthesis) which directly gives you the length of list.
Also you dont store the result anywhere so thats why i said its useless. You may want to store the total count. then you can do this.
public int TotalCount
{
get { return staff.Count + students.Count; }
}

Casting contents of an indexer's returned collection?

I have a table/row/column data structure setup. There is a string-based indexer in the DtaTable class to return DtaRows, and another on the DtaRow class to return DtaColumns. So you can write things like...
return theTables["tablename"]["rowidentifier"]["columnname"];
In actuality, the objects inside the tables are not DtaRows, but one of about three dozen subclasses, like InflationRow and CurrencyRow. Each table contains only objects of those types, so for instance...
theTables["Inflations"]["General"];
always returns an InflationRow.
Now to make this easier to access from C#, I have a bunch of methods at a higher level like...
public DtaTable Inflations { get {return pTables["Inflations"];} }
Now the problem I'd like to solve is that when someone calls one of these methods, they don't get an InflationRow, because DtaTable has DtaRows. So for instance...
MyInfRow = Inflations["General"];
returns a DtaRow. So I have to cast all the time...
MyInfRow = (InflationRow)Inflations["General"];
I want to get rid of all the casting.
The only solution I have found so far is to make 36 new subclasses of the table object, each overriding the indexer return type. This seems worse than the casting.
Is there some simpler way to do this?
It you know that callers are only primarily going to use another indexer, you can introduce a generic class providing that:
public class SpecializedTable<T>
{
private readonly DtaTable table;
// Just in case anyone really wants this
public DtaTable Table { get; }
public SpecializedTable(DtaTable table)
{
this.table = table;
}
public T this[string row] { get { return (T) (object) table[row]; } }
}
As an aside, these DtaTable etc names feel annoying unpronounceable / easily confusable with the .NET DataTable classes. If you're in a position to rename them, I'd suggest you do so.
Then your Inflations property can be:
public SpecializedTable<InflationRow> Inflations
{
get
{
return new SpecializedTable<InflationRow>(pTables["Inflations"]);
}
}
You may want to cache this to avoid creating a new object each time you call the property though.
At that point, this code: Inflations["General"] will perform the cast appropriately for you.
Use as instead of direct cast. If casting is valid it will return the instance, otherwise it will stay as NULL.
public MyInfRow Inflations { get {return pTables["Inflations"] as MyInfRow } }

C# method parameter being a property of the class

First of all, apologies if I posted it in the wrong place, I'm new here and I'm not sure if I posted in the right place.
Well, I'm trying to build a generic search method, where I'll add search parameters to mount a SQL Query and execute it on the database. All that using C#. My goal is that the parameter corresponding to the field I'll search, to be a property of the class the method is in. For example:
public foo
{
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
public void AddSearchParameter(???, EnumOperator Operator, object Value)
}
Whenever I want to specify a parameter to add on the search, I would like it to look like this:
foo xxx = new foo();
xxx.AddSearchParameter(foo.CustomerCode, EnumOperator.Equal, txtCustomerCode.text);
My question is how to do it?
If you are trying to pass the member information (so that the AddSearchParameter can inspect the MemberInfo and write suitable SQL), then you'd need to use either a string literal (i.e. "CustomerCode"), or an expression tree. The latter is richer, but involves learning the Expression<T> API. But fundamentally:
public void AddSearchParameter(Expression<Func<object>> expression, ...)
...
xxx.AddSearchParameter(() => foo.CustomerCode, ...)
This, however, is not a trivial area of .NET.
If I were doing something like this, I would probably make the Search() method on foo check for the existence of values in the various this properties, and then build the query based on that.
public List<Results> Search()
{
if (!String.IsNullOrEmpty(this.CustomerCode))
{
// add search value to query
}
// etc.
}

Categories