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.
Related
I know that in a widening conversion, the destination data type can hold any value provided by the source data type. I can understand this when convert value type,
but can't between reference types. My question arises from follows scenario:
public class Person
{
public string Name { get; set; }
}
public class Employee : Person
{
public string SurName { get; set; }
}
static void Main(string[] args)
{
Employee emp = new Employee { Name = "Elvin", SurName = "Mammadov" };
Person prs = emp;
}
As shown, the Person class is ancestor class of Empoyee. In previouse code, I create reference of Emplyee class, and then convert Employee object into a Person. At this point, I lose SurName data field and value.
I want to know:
Is it countary to can hold any value expression?
Why conversion a reference type to a direct or indirect ancestor class or interface is a widening conversion?
thanks for reply
It would be called a 'widening conversion' because you're becoming less specific with regard to the references type, you're widening the set of potential types. When you have an Employee reference you know that you can use any functionality specific to that class, when you have a Person reference to the same object you only know that you can use functionality contained in the Person class. If you want to use Employee specific functionality with your prs reference you'll first have to cast your reference back to an Employee reference and if prs isn't actually of type Employee (perhaps it's of type Customer which also inherits from Person) then you will get an InvalidCastException.
The SurName property does not go away when you're dealing with a Person reference. You just cannot access it because it is not contained within the Person class. Basically, if you have a reference of the base classes type, you will only be able to access properties/methods contained within the base class. It doesn't matter that it is actually an Employee, you have a Person reference, so the object is treated accordingly.
The conversion is not useful in your example. The conversion is useful when you're attempting to work with many child classes in a generic manner. As an example, I may have a Person class. In addition to that I have Employee, Customer, and Consultant classes which inherit from it. Now lets suppose I have a Store object and I want to do something like get the names of every Person who is currently in the store. The simplest way to solve this problem would be to have a List<Person> with all the people in the store. Because Employee, Customer, and Consultant all inherit from Person I could do
peopleInMyStore.Add(MyEmployee);
peopleInMyStore.Add(MyCustomer);
peopleInMyStore.Add(MyConsultant);
Then later on I can do something like;
foreach (Person p in peopleInMyStore)
{
Console.WriteLine(p.Name);
}
This concept is referred to as 'polymorphism' and can be read about here http://en.wikipedia.org/wiki/Polymorphism_(computer_science)
My example is contrived, but this is one of the main reasons you use inheritance. To give you a real example I have some test code where I have a class called ApiTestSuite then I have about a dozen classes that all inherit from it of the form SpecificApiTestSuite. The project builds into a command line executable, you invoke it with an api parameter (api=specificApiName) then I can do something like;
ApiTestSuite tests;
if (args[0] == "api1")
tests = new Api1TestSuite();
else
tests = new Api2TestSuite();
tests.RunTests();
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.
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;
}
}
My understanding is any method which does not modify state of the constaining class is a prime candidate to be made static because it does not touch the instance. An instance would be that containing class's data (fields/properties) so if I had a person class with a property called Name (and just that one property), and I am not modifying that property then my class can be set as static, but of course, but the function could be working with another object. Is this the right thing to look for when checking if a method should be made static?
Static variables are described as global variables, but what is the difference of this to any publicly variable? All the variables are in the server's memory and will be lost in a reboot etc. And then use this variable to hold expensive-to-get data (eg running stored procedures in a loop etc).
Thanks
My understanding is any method which does not modify state of the constaining class is a prime candidate to be made static because it does not touch the instance.
I wouldn't say it's a prime candidate, but rather just a candidate. Personally, I think methods should be made static if the API would suggest that it should be static from a logical, algorithmic standpoint. Technically, any method which doesn't change state can be static, but I don't believe it necessarily should be static.
and I am not modifying that property then my class can be set as static, but of course, but the function could be working with another object.
You can only set your class as static in C# if it has absolutely no instance variables. "Instances" of a static class don't exist (and cannot exist), nor can non-static members.
Now - for what I think you're really after...
The difference between a static variable and a non-static variable has to do with how it's accessed. When you define a static field on a class, you're defining a field that will always have a single instance (instance of the field) tied to the class itself. When you define a non-static, normal field, on the other hand, you will potentially have many instances of your field, each residing within one instance of your class.
This is why static variables are often described as global - anything that has access to the class has access to it's one copy of the static variable (provided its publicly accessible). However, non-static fields are different - you need to have a reference to the specific instance of the class in order to read or write to a non-static member.
.
My understanding is any method which
does not modify state of the
constaining [sic] class is a prime candidate
to be made static because it does not
touch the instance.
I don't think this is the right way to think of static vs. non-static. Rather, any method which is not related to the state of a class instance can be static. A name is obviously associated with a particular person, so a Name field on a Person class should almost certainly not be static. Otherwise, you could end up with a scenario like this:
public class Person {
public static string Name { get; set; }
public Person(string name) { Name = name; }
public override string ToString() {
return Name;
}
}
Person dan = new Person("Dan";
Person john = new Person("John";
// outputs "John"
Console.WriteLine(john);
// outputs "John" again, since Dan doesn't have a name property all his own
// (and neither does John, for that matter)
Console.WriteLine(dan);
EDIT: Now, suppose we have a property such as House which can belong to not one but several people. blade asks: "How would this be modeled in code - static?"
My answer: NO, for the same reason already mentioned above. Suppose I've fixed the problem above by making the Name property non-static. Then I introduce a new static House property. Now I have a situation like this:
public class Person {
public string Name { get; set; }
public static House House { get; set; }
public Person(string name, House house) {
Name = name;
House = house;
}
public override string ToString() {
return String.Concat(Name, ", ", House);
}
}
public class House {
public double SquareFootage { get; set; }
public House(double sqft) { SquareFootage = sqft; }
public override string ToString() {
return String.Format("House - {0} sq. ft.", SquareFootage);
}
}
House danAndKatsHouse = new House(1000.0);
House johnsHouse = new House(2000.0);
Person dan = new Person("Dan", danAndKatsHouse);
// outputs "Dan, House - 1000 sq. ft." as expected
Console.WriteLine(dan);
Person kat = new Person("Kat", danAndKatsHouse);
// outputs "Kat, House - 1000 sq. ft.", again as expected
Console.WriteLine(kat);
Person john = new Person("John", johnsHouse);
// outputs "John, House - 2000 sq. ft.", so far so good...
Console.WriteLine(john);
// but what's this? suddenly dan and kat's house has changed?
// outputs "Dan, House - 2000 sq. ft."
Console.WriteLine(dan);
There's a difference between multiple objects of one class sharing the same object and ALL objects of that class sharing the same object. In the latter case, a static property makes sense; otherwise, it does not.
There are a few ways off the top of my head to deal with this scenario. They are:
1. Make the House property non-static
It might seem strange, but you can always just make the House property non-static and you won't ever have to worry about the problem above. Furthermore, assuming you actually do assign the same House object to each Person who shares it, making a change to the House through one Person object will actually achieve the desired effect:
House danAndKatsHouse = new House(1000.0);
// (after making Person.House property non-static)
Person dan = new Person("Dan", danAndKatsHouse);
Person kat = new Person("Kat", danAndKatsHouse);
dan.House.SquareFootage = 1500.0;
// outputs "1500"
Console.WriteLine(kat.House.SquareFootage);
This could actually be a problem, however, if you accidentally assign the same House to two people with the intention of them actually having two different Houses:
House smallerHouse = new House(1000.0);
House biggerHouse = new House(2000.0);
Person dan = new Person("Dan", smallerHouse);
Person john = new Person("John", biggerHouse);
Person bill = new Person("Bill", smallerHouse);
bill.House.SquareFootage = 1250.0;
// yikes, Dan's house just changed...
Console.WriteLine(dan);
2. Use a database
The fact is that the notion of making a house a property of a person is somewhat a forced concept to begin with. A person may move out of their house, different people may move in, etc. Really a relationship exists between the two, which makes using a database an appropriate solution.
Using this approach, what you'd do is have a Persons table, a Houses table, and a third table (maybe PersonHouses) containing id pairs from the other two tables to represent, I guess, home ownership.
If you don't have a full-blown database at your disposal, you can achieve effectively the same result (in .NET) using a System.Data.DataSet and its collection of System.Data.DataTable objects in your code. However, in any scenario where you are translating rows of a database (or DataTable) to objects and then back again, you do need to be aware of impedence mismatch. Basically, whatever meticulous precautions you take in your code to encapsulate your data are out the window once that data is in the database, ready to be modified by anyone with sufficient permissions.
3. Use dictionaries
Another approach, similar to using a database but a bit more work (and I think some programmers who've gone the DataSet route shudder at the thought of this), is to use dictionaries to keep track of your Person and House objects. The quickest way to implement this approach would be to have a Dictionary<int, Person> and a Dictionary<int, House>, and assign each Person a HouseId property:
public class Person {
public int Id { get; private set; }
public string Name { get; set; }
public int HouseId { get; set; }
private static int LastIdValue { get; set; }
private static Dictionary<int, Person> People { get; set; }
static Person() {
LastIdValue = 0;
People = new Dictionary<int, Person>();
}
// make the constructor private to disallow direct instantiation
private Person(int id, string name, int houseId) {
Id = id;
Name = name;
HouseId = houseId;
}
// only permit construction through this function, which inserts
// the new Person into the static dictionary before returning it
static public Person NewPerson(string name, int houseId) {
Person p = new Person(LastIdValue++, name, houseId);
People.Add(p.Id, p);
return p;
}
static public Person getPersonById(int id) {
Person p = null;
return People.TryGetValue(id, out p) ? p : null;
}
}
public class House {
public int Id { get; private set; }
public int SquareFootage { get; set; }
private static int LastIdValue { get; set; }
private static Dictionary<int, House> Houses { get; set; }
static House() {
LastIdValue = 0;
Houses = new Dictionary<int, House>();
}
// make the constructor private to disallow direct instantiation
private House(int id, int sqft) {
Id = id;
SquareFootage = sqft;
}
// only permit construction through this function, which inserts
// the new House into the static dictionary before returning it
static public House NewHouse(int sqft) {
House h = new House(LastIdValue++, sqft);
Houses.Add(h.Id, h);
return h;
}
static public House getHouseById(int id) {
House h = null;
return Houses.TryGetValue(id, out h) ? h : null;
}
}
House firstHouse = House.NewHouse(1000.0);
House secondHouse = House.NewHouse(2000.0);
Person dan = Person.NewPerson("Dan", firstHouse.Id);
Person kat = Person.NewPerson("Kat", firstHouse.Id);
Person john = Person.NewPerson("John", secondHouse.Id);
House dansHouse = House.getHouseById(dan.HouseId);
House katsHouse = House.getHouseById(kat.HouseId);
// this prints
if (katsHouse == dansHouse) { Console.WriteLine("Dan and Kat live in the same house."); }
// this also prints
if (dansHouse == firstHouse) { Console.WriteLine("Dan and Kat live in the first house."); }
// this does not print
if (dansHouse == secondHouse) { Console.WriteLine("Dan and Kat live in the second house."); }
This way, all your data encapsulation still holds. However, if you ever need your data to persist between instances of your code running, then you need to serialize your dictionaries in some file format (most likely XML), which could then be edited by anyone with sufficient privileges, and then you're back to the impedence mismatch problem of using a database all over again.
In light of the advantages and disadvantages of each approach, I think what actually makes the most sense -- and makes your life easiest -- is to simply make House a non-static property. This is assuming you don't have tons and tons of Person and House objects to keep track of.
" if I had a person class with a
property called Name (and just that
one property), and I am not modifying
that property then my class can be set
as static"
That is not correct. A person class is almost certainly a domain entity. It is conceivable you might want to have a static method on a Person entity, but I haven't ever come across one. In your example, you would have a private setter for your 'Name' property.
The static-ness of anything should model your domain, rather than being a language implementaion detail.
There are no true globl variables in C#, in the sense that that term is used in other languages like C. The difference between a static object and a global object is that a static object has permissions that are relative to the class in which it is defined. This is a very good thing, because you can create private static members that are only accessible to member of one class. The big problem with the abuse of global variables is the many depenencies to a single global variable that can evolve across a large colleciton of modules. Private static object avoid this problem.
One big problem with static objects is that they are not thread safe. In order to declare a thread safe static object, you must use the ThreadStatic attribute and provide a way for the object to be initialized on first access. You should do this for all multi-threaded environents e.g. ASP.NET, and any general purpose library that might run in multi-threaded environment. Heck, just always do this and you won't be sorry!
If you have a Person class with a static field name:
public class Person {
public static string Name { get; set; }
}
then you can only ever have one name. You can not have a list of persons with different names. Static can be seen as "Unique" in the way that it's value is global. This can be a trap in ASP.net applications by the way, because static applies through the entire application, which means to all users.
Static variables are rather rare and used for data that is really not part of a specific instance of the class. Or to return specific instances.
For example, Guid.Empty is a static field that returns a Guid that has all Bits set to 0.
A good example is System.Drawing.Color. Color has instance-specific variables, for example R,G,B and Alpha, but you have static fields like Color.Black which returns a Black color.
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...
}