how to extend base class functionality - c#

I have a class:
public class Person {
public string FirstName = "";
public string LastName = "";
}
and a derived class:
public class HRPerson : Person {
public string GetSomething() {
//calculate something
}
}
Essentilly, I'm wanting to extend the functionality of the base class. The use looks like this, where GetAllPerson returns List<Person>.
class Program
{
static List<HRPerson> GetAllHRPerson()
{
List<HRPerson> HRPersonList = new List<HRPerson>();
foreach (Person person in GetAllPerson)
{
HRPersonList.Add(person);
}
return HRPersonList;
}
}
It doesn't compile, saying that there is no overload for the parameter, and when I try to cast person to HRPerson, I get the runtime error "unable to cast object of type Person to type HRPerson" error.
How do I go about adding additional functionality like this?

It sounds like your GetAllPerson is returning some non-HR people...
Assuming that's the case and you just want to filter those out, it's easiest to use LINQ's OfType method:
static List<HRPerson> GetAllHRPerson()
{
return GetAllPerson().OfType<HRPerson>().ToList();
}
(Side note: please avoid public fields like this, other than for constants. Fields should be an implementation detail, not part of your public API.)
Of course if none of your Person instances are actually instances of HRPerson, that's not going to help you. You can't change the type of an instance once it's been created. It's not really clear what your situation is - if this answer doesn't help you, please provide more details.
EDIT: I'm still not really sure that you want an extension method, but if you do, it would be something like:
public static class PersonExtensions
{
public static string GetSomething(this Person person)
{
// Do something with the given Person
}
}
You can then call that on any Person as if it were an instance method:
Person person = ...;
string something = person.GetSomething();
But this is not polymorphic - it's not that you're changing anything about the Person object, which your description still makes it sound like you really want to do...

Based on your comments to Jon Skeet's answer, is this what you are looking for:
Create a subclass of Person, for example, NamedPerson. Give NamedPerson a method GetFullName, which returns the full name of the Person.
Then create a subclass HRPerson from NamedPerson, and override GetFullName to return the name in a slightly different format. CCPerson would also be subclassed from NamedPerson.
You have no control over Person, but you have full control over NamedPerson. Then what you want is a list of NamedPersons, not of HRPersons. This list could contain bare NamedPersons, or HRPersons, or CCPersons, but all objects on the list would be NamedPersons or subclasses of it, so they would all have GetFullName.

Related

Modify a C# Class to be a Collection

Below is a Person class. Currently, it can only be used to instantiate a single Person object. I would like to change it so it can accept a list of full names and result in a collection of Person objects.
using System;
namespace Test
{
public class Person
{
public string FullName;
public string Organization;
public Person(string Organization, string FullName)
{
this.FullName = FullName;
this.Organization = Organization;
}
}
}
This would ideally be similar to the Fileinfo class. This class can be initialized by either providing a single file name or a list of file names. I would also like to be able to initialize this Person class to be constructed using either a list of full names or a single name.
I don't think the FileInfo class works the way you're expecting—but I now understand what you're asking. As mentioned in the comments, you're going to need two classes. The first one is for your business object—in this case Person. The second one will be a collection-based class, such as PersonCollection.
As an alternative, you can alter your data model so that you have a separate Organization and Person class. In that model, your Person class would have a FullName property, but not an Organization property. I'll address that option at the end.
Instead of just offering code, I'll attempted to explain the concepts as I go, while also flagging issues you're likely going to run into along the way. That makes for a longer post. But given the nature of the question, I hope this additional detail will prove valuable.
Business Object
Your Person class can continue to operate exactly the way you've proposed. That said, there are a couple of improvements you might consider.
First, if your business object is never going to be modified after you've instantiated it—i.e., it's immutable—then you can use the C# 9.0 record syntax, which allows your constructor to define properties directly:
public record Person(string Organization, string FullName);
Alternatively, if you prefer to keep this as a class, then I'd recommend implementing it as follows:
public class Person
{
public string Organization { get; set; }
public string FullName { get; set; }
public Person(string organization, string fullName)
{
Organization = organization;
FullName = fullName;
}
}
Notes
I've used the auto-implemented property syntax for Organization and FullName; otherwise, they will be treated as public fields, which have slightly different semantics (source).
I've updated your parameter names to be camelCase, so you don't need to assign property values with the this prefix. This is standard in C#.
I think it's more intuitive for the fullName to be your first parameter, but that's a stylistic preference, so I've kept this consistent with your original code.
Collection-Based Class
There are a number of ways to create a strongly typed collection-based class. The easiest is to simply inherit from Collection<Person>:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people)
{
Add(person);
}
}
}
Notes
You could also call this People, as I did in the comments, but Microsoft recommends that strongly typed collection classes start with the item type (i.e., Person) and end with Collection (source).
You could also derive from e.g., List<Person>, but Microsoft recommends using the more familiar Collection<> class (source).
The params keyword allows you to accept an array—in this case of Person objects—but pass them as a list of parameters, instead of an array (details). This makes for a friendlier and more intuitive interface in this case.
You could instead accept an array of strings—e.g., fullNames—in order to construct a new Person object for each one, as you requested. But as your current Person object also needs an Organization parameter, it's easier to first construct the Person object, and then pass it to the collection.
Usage
You can now construct the class by creating some Person instances and passing them to the PersonCollection constructor as follows:
//Construct some Person objects
var robert = new Person("Robert, Inc.", "Robert");
var jeremy = new Person("Ignia, LLC", "Jeremy")
//Construct a new PersonCollection
var people = new PersonCollection(robert, jeremy);
Alternatively, if you're using C# 9.0 (e.g., with .NET 5+), and are hard-coding your Person initializers, you can also use the following syntactical shorthand:
var people = new PersonCollection(
new ("Robert, Inc.", "Robert"),
new ("Ignia, LLC", "Jeremy")
);
This looks similar to your request to pass in a list of full names—except that it accounts for your Organization property, and results in a full Person object for each. If you'd truly prefer to just pass in an array of names, see Organization-Based Model at the end of this answer.
Validation
In practice, you probably want to add in some validation to ensure that each Person reference is not null, and that at least one Person instance is passed to your constructor. If so, you can extend this to include some validation. Here's one possible approach to that:
public class PersonCollection: Collection<Person>
{
public PersonCollection(params Person[] people)
{
foreach (var person in people?? Array.Empty<Person>())
{
if (person is null)
{
continue;
}
Add(person);
}
if (Count == 0)
{
throw new ArgumentNullException(nameof(people));
}
}
}
I default to the Array.Empty<Person> on the loop so that we don't need to do two checks—first for the people length, and then for the PersonCollection length. But you can adjust to your preferences.
Organization-Based Model
In the comments, you proposed an alternate constructor:
public People(string Organization, string[] FullName) { … }
This implies a different data model. If you're going to have one organization that can have multiple Persons associated with it, I'd instead create an Organization business object:
public record Person(FullName);
public class Organization
{
public readonly string Name { get; }
public readonly Collection<Person> Members { get; }
public Organization(string name; params string[] members)
{
Name = name?? throw new ArgumentNullException(nameof(name));
foreach (var memberName in members)
{
Members.Add(new Person(memberName));
}
}
}
Notes
In this model, each Organization has a Name and then multiple Members—each represented by a Person object.
Because the organization name is handled at the Organization level, it is presumably not needed on each Person object.
The Members collection could be replaced with a Collection<string> if you just need a list of names. But maintaining a Person object offers more flexibility.
You can obviously incorporate the previously proposed validation logic into this constructor as well.
You could also add an overload of the constructor that accepts a Person[] array to offer more flexibility.

Can I create an object in one function and constructing in another?

So I got an assignment [college student] to create a program that runs a garage. I have a class for every car type [FuelMotorcycle, ElectricMotorcycle, FuelCar, ElectricCar, etc.], each car type has its own constructor and they all differ from one another.
One of the assignment requirements is to "place the code that creates car objects [new], and this code alone, in a class on the logical part of the program, this code part cannot turn to the user directly or indirectly" (translated).
So the way I see it, I have a class, let's say "EmptyCarCreator" , that will have methods such as:
public static FuelMotorcycle CreateNewFuelMotorcycle()
{
FuelMotorcycle EmptyFuelMotorcycle;
return EmptyFuelMotorcycle;
}
obviously this won't compile, and even if it did, I couldn't use the "FuelMotorcycle" class constructor after I get it returned.
I need the user to input the elements for the constructor.
So, is there any other way to do this? I feel like I am missing something very basic here.
Please excuse any English errors, hope my question was clear.
You would need something like this:
public static class EmptyCarCreator
{
public static T Create<T>() where T : class, new()
{
return new T();
}
}
Then you would use it like this:
FuelMotorcycle myVehicle = EmptyCarCreator.Create<FuelMotorcycle>();
This will create a new class through the parameterless constructor.
There are other options that might be able to handle parameters a little better like this:
public static class EmptyCarCreator
{
public static object Create(Type type)
{
return Activator.CreateInstance(type);
}
}
To use this you would have to cast this returned object.
FuelMotorcycle myVehicle = (FuelMotorcycle)EmptyCarCreator.Create(typeof(FuelMotorcycle));

"Writable" reference to object

Not sure I'm able to formulate this question in a way someone would simply understand, so lets have a cool marketing example:
public class Part
{
public MemberType member;
...
}
public class Product
{
public Part part1;
...
}
...
Product product = new Product();
I need to modify the public product's part1. So, the natural method is to write something like:
product.part1 = new Part();
Now, an algorithm (let's say a sort of search one) would go through the product object and identify the part1 as an interesting part and returns reference to it:
Part Search(Product product)
{
Part part = null;
...
part = product.part1;
...
return part;
}
...
interesting_part = Search(product);
We can alter the product object via the interesting_part like
interesting_part.member = whatever;
Now, the question: in c/c++ if the Product.part1 is pointer to Part and Search returns address of this pointer, we could replace the part1 just by assigning new value to this address. AFAIK this is not possible for c# reference:
interesting_part = new Part();
Just creates new object and copies its reference to the interresting_part, but without knowing the member parent (product object), we are not able to modify the (product.part1) reference, just its content. We would need second level of the reference.
Is there something like "ref reference" type which would accept reference addresses? In such hypothetical case the search would return ref Part and assigning to such value would replace the referenced object with the new one.
Thanks.
You could create a Reference class
class Reference<T>
{
private Func<T> m_Getter;
private Action<T> m_Setter;
public Reference(Func<T> getter, Action<T> setter)
{
m_Getter = getter;
m_Setter = setter;
}
public T Value
{
get{return m_Getter();}
set{m_Setter(value);}
}
}
Now you can say
Reference<Part> Search(Product product)
{
Part part = null;
...
part = product.part1;
var reference=new Reference<Part>(()=>product.part, (value)=>product.part1=value);
return refernce;
}
var partReference = Search(product);
partReference.Value = someNewPart;
In a very similar situation, I keep a reference of the parent in each child object. Simple and works.
public class Part
{
public MemberType member;
...
public Product parent;
Part(Product p)
{
parent = p;
}
}
public class Product
{
public Part part1;
...
}
I don't think you can do that. You would need to mutate a reference to you product object, or have some other added layer of reference.
So you need to build a Proxy object. The Product would get a reference to the Proxy and the (hidden) Part can be exchanged. This is a common OO design pattern. Of course the Proxy can delegate method calls to the Part.
If you want to change the field, you can do this,
class Program
{
static void Main(string[] args)
{
var holder = new Holder();
holder.CurrentPart = new Part() { Name = "Inital Part" };
Console.WriteLine(holder.CurrentPart.Name);
TestRef(ref holder.CurrentPart);
Console.WriteLine(holder.CurrentPart.Name);
Console.ReadKey();
}
public static void TestRef(ref Part part)
{
part = new Part() { Name = "changed" };
}
}
public class Part
{
public string Name;
}
public class Holder
{
public Part CurrentPart;
}
This won't work with property, indexers and so.
As far as I know, there isn't any way to alter an object's "parent" without having a reference to it. So I believe the official answer to your question as written is "no".
That said, there are many ways to accomplish the task as written. The easiest option is to add a reference to the parent from the part object. You end up with something like:
public class Part
{
public Product parentProduct;
public MemberType member;
...
}
Now whenever you have a part object you also know what product the part goes with (IF it does indeed go with a part at all). This is not necessarily a bad coding style but there certainly are pitfalls. You can update the product, but forget to update the parts in that product, you are coding so that parts have one product, but what if that part has many products? You can see how this works, but it can get complicated.
Taking this and making it more generic you can have reference the parent as an object type. That looks like:
public class Part
{
public object parent;
public MemberType member;
...
}
Now when you want to use the parent you can write something like:
var parentProduct = myPart.parent as Product;
This will convert the parent to a product or will assign null if the parent is not of the type Product. Now parts can have parents of any given type you would want and you have made the pattern more flexible.
One final pattern I know people use frequently is delegates. This allows you to pass in a function effectively modifying the way "search" is working. Say what you really want to do is search, then process the results in some manner, but you want that processing to be flexible (this may be what you were doing with the results). In that case, you can use delegates as follows:
// define the delegate
public delegate void ProcessResultDelegate(Product result, Part interestingPart);
// an example search function
public static void RunSearch(IEnumerable<Product> products, ProcessResultDelegate processingHelper)
{
// run the search... then call the processing function
processingHelper(searchResult, interestingPart);
}
This pattern is more useful when you want to modify the behavior of a routine rather than the return value from that routine.
Anyways, hope these patterns help some!

Is it bad practice to modify the variable within a method?

Which method style is better?
Is it generally bad practice to modify the variable within a method?
public class Person
{
public string Name { get; set;}
}
//Style 1
public void App()
{
Person p = new Person();
p.Name = GetName();
}
public string GetName()
{
return "daniel";
}
//Style 2
public void App()
{
Person p = new Person();
LoadName(p)
}
public void LoadName(Person p)
{
p.Name = "daniel";
}
There are times when both styles may make sense. For example, if you're simply setting the name, then perhaps you go with the first style. Don't pass an object into a method to mutate one thing, simply retrieve the one thing. This method is now more reusable as a side benefit. Think of it like the Law of Demeter or the principle of least knowledge.
In other cases, maybe you need to do a wholesale update based on user input. If you're displaying a person's attributes and allowing the user to make modifications, maybe you pass the object into a single method so that all updates can be applied in one spot.
Either approach can be warranted at different times.
I think the code is more clear and readable when methods don't change objects passed. Especially internal fields of passed object.
This might be needed sometimes. But in general I would avoid it.
Updated based on comment (good point)
I agree with Anthony's answer. There are times when both styles may make sense.
Also, for more readability you can add the LoadName function in person class.
public void App()
{
Person p = new Person();
p.LoadName(); //If you need additional data to set the Name. You can pass that as Parameter
}
You are accessing the data using properties which technically is by a methods. What you are worried is property accessing iVar or internal variable. There reason why it is generally bad to allow access of iVar is because anyone can modify the variables without your knowledge or without your permission, if its through a methods (properties), you have the ability to intercept the message when it get or set, or prevent it from getting read or write, thus it is generally said to be the best practice.
I agree with Ron. Although your particular example could be slightly contrived for posting reasons, I would have a public getter for Name, and a private setter. Pass the name to the constructor, and the Name property will get set there, but afterwards can no longer be modified.
For example:
public class Person
{
public string Name { get; private set; }
public Person( string name)
{
Name = name;
}
}

Constructors with the same argument type

I have a Person object with two constructors - one takes an int (personId), the other a string (logonName). I would like another constructor that takes a string (badgeNumber). I know this can't be done, but seems it might be a common situation. Is there a graceful way of handling this? I suppose this would apply to any overloaded method. Code:
public class Person
{
public Person() {}
public Person(int personId)
{
this.Load(personId);
}
public Person(string logonName)
{
this.Load(logonName);
}
public Person(string badgeNumber)
{
//load logic here...
}
...etc.
You could perhaps use factory methods instead?
public static Person fromId(int id) {
Person p = new Person();
p.Load(id);
return p;
}
public static Person fromLogonName(string logonName) {
Person p = new Person();
p.Load(logonName);
return p;
}
public static Person fromBadgeNumber(string badgeNumber) {
Person p = new Person();
// load logic
return p;
}
private Person() {}
You might consider using custom types.
For example, create LogonName and BadgeNumber classes.
Then your function declarations look like...
public Person(LogonName ln)
{
this.Load(ln.ToString());
}
public Person(BadgeNumber bn)
{
//load logic here...
}
Such a solution might give you a good place to keep the business logic that governs the format and usage of these strings.
You have four options that I can think of, three of which have already been named by others:
Go the factory route, as suggested by several others here. One disadvantage to this is that you can't have consistent naming via overloading (or else you'd have the same problem), so it's superficially less clean. Another, larger, disadvantage is that it precludes the possibility of allocating directly on the stack. Everything will be allocated on the heap if you take this approach.
Custom object wrappers. This is a good approach, and the one I would recommend if you are starting from scratch. If you have a lot of code using, e.g., badges as strings, then rewriting code may make this a non-viable option.
Add an enumeration to the method, specifying how to treat the string. This works, but requires that you rewrite all the existing calls to include the new enumeration (though you can provide a default if desired to avoid some of this).
Add a dummy parameter that is unused to distinguish between the two overloads. e.g. Tack a bool onto the method. This approach is taken by the standard library in a few places, e.g. std::nothrow is a dummy parameter for operator new. The disadvantages of this approach are that it's ugly and that it doesn't scale.
If you already have a large base of existing code, I'd recommend either adding the enumeration (possibly with a default value) or adding the dummy parameter. Neither is beautiful, but both are fairly simple to retrofit.
If you are starting from scratch, or only have a small amount of code, I'd recommend the custom object wrappers.
The factory methods would be an option if you have code which heavily uses the raw badge/logonName strings, but doesn't heavily use the Person class.
No.
You might consider a flag field (enum for readability) and then have the constructor use htat to determine what you meant.
That won't work. You might consider making a class called BadgeNumber that wraps a string in order to avoid this ambiguity.
You cannot have two different constructors/methods with the same signature, otherwise, how can the compiler determine which method to run.
As Zack said, I would consider creating an "options" class where you could actually pass the parameters contained in a custom type. This means you can pretty much pass as many parameters as you like, and do what you like with the options, just be careful you dont create a monolithic method that tries to do everything..
Either that, or vote for the factory pattern..
You could use a static factory method:
public static Person fromLogon(String logon) { return new Person(logon, null); }
public static Person fromBadge(String badge) { return new Person(null, badge); }
As has been suggested, custom types is the way to go in this case.
If you are using C# 3.0, you can use Object Initializers:
public Person()
{
}
public string Logon { get; set; }
public string Badge { get; set; }
You would call the constructor like this:
var p1 = new Person { Logon = "Steve" };
var p2 = new Person { Badge = "123" };
Only thing I can think of to handle what you're wanting to do is to have to params, one that describes the param type (an enum with LogonName, BadgeNumer, etc) and the second is the param value.
You could switch to a factory style pattern.
public class Person {
private Person() {}
public static PersonFromID(int personId)
{
Person p = new Person().
person.Load(personID);
return p;
this.Load(personId);
}
public static PersonFromID(string name)
{
Person p = new Person().
person.LoadFromName(name);
return p;
}
...
}
Or, as suggested, use custom types. You can also hack something using generics, but I wouldn't recommend it for readability.
Depending on your business constraints:
public class Person
{
public string Logon { get; set; } = "";
public string Badge { get; set; } = "";
public Person(string logon="", string badge="") {}
}
// Use as follow
Person p1 = new Person(logon:"MylogonName");
Person p2 = new Person(badge:"MyBadge");
How about ...
public Person(int personId)
{
this.Load(personId);
}
public Person(string logonName)
{
this.Load(logonName);
}
public Person(Object badgeNumber)
{
//load logic here...
}

Categories

Resources