A good design to pack parameters? - c#

I have an object that takes plenty of parameters to its constructor (from 9 to 13 depending on use).
I want to avoid the ugliness of new MyObject(param1, param2, param3 ... param13).
My first attempt was to create a class MyObjectParams with properties with public getters and setters, it gives something like that :
var objectParams = new MyObjectParams
{
Param1 = ...,
Param2 = ...,
...
};
I see some big projects like SlimDX for their PresentParameters use this design. It looks better. But the class is not immutable.
I'd like my MyObjectParams to be immutable while still using a clean construction style. This is how it would look like with an immutable class :
var objectParams = new MyObjectParams
(
param1,
param2,
...
);
Note: it's just the long constructor line broken into several, so it's cleaner but still not as readable as initializers.
I was thinking of using named parameters to get both an immutable class and a more or less clean code, but I'm not sure whether this actually is a good idea:
var objectParams = new MyObjectParams
(
param1: ...,
param2: ...,
...
);
Should I use named parameters? Can you think of a better approach to solve this problem?
Edited regarding an answer below: unfortunately, I don't really think the design is bad. The 9 parameters really are required and remain constant throughout the entire life of the object. I cannot provide a default value for them as it is completely usage-dependant.

Have you looked into designing a solution in which you wouldn't need this amount of parameters? Having a lot of parameters makes the code very tightly coupled which reduces maintainability. Maybe you can redesign a small amount of code to a design which better separates the responsibilities of the class?

I really like the way The Zen of Python says a few things:
Simple is better than complex.
Complex is better than complicated.
[...]
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
I believe that having a dedicated Options class of some kind with the exhaustive list of all possible parameters is a good idea. Allow your MyObject constructor to require an Options instance, and then store a reference to the instance as a field on MyObject and refer to its getters/setters. (Storing the reference will be much superior to trying to parse the options and transfer their values to the MyObject instance. Now that would be messy.) With all data access delegated to the Options class, you will have successfully encapsulated the object's configuration, and you've designed a simple API for option access as the same time.
If Options has no reason to be publicly accessible, make it a private class definition and then you're free to maintain changes to Options logic without modifying MyObject. I believe that is a fair solution to you as the developer, and doesn't commit atrocities.

The constructor could have only a small number of parameters, the ones required for proper object initialization. You could then have a number of properties that can be set after the object has been constructed. You can set default values for those properties in the constructor and the client can set the ones he/she requires.
class Person
{
public Person(string name, int age)
{
Name = name;
Age = age;
Address = "Unknown";
Email = "Unknown";
}
public string Name {get; private set;}
public int Age {get; private set;}
public string Email {get; set;}
public string Address {get; set;}
}
Person p = new Person("John Doe", 30);
p.Email = "john.doe#example.org";

You could use the builder pattern to construct an immutable object.
public sealed class ComplexObject
{
public int PropA { get; private set; }
public string PropB { get; private set; }
public sealed class Builder
{
int _propA;
string _propB;
public Builder SetPropA(int propA)
{
// validate
_propA = propA;
return this;
}
public Builder SetPropB(string propB)
{
// validate
_propB = propB;
return this;
}
public CustomObject ToCustomObject()
{
return new CustomObject
{
PropA = _propA,
PropB = _propB
};
}
}
}
Usage
var custom =
new CustomObject.Builder()
.SetPropA(1)
.SetPropB("Test")
.ToCustomObject();
Final Thoughts
Despite my previous suggestion I am in no way against using named parameters if they are available.

Related

Passing runtime parameters throughout application

I have a legacy C# library (a set of interrelated algorithms) in which there is a global god object which is passed to all classes. This god object (simply called Manager :D ) has a Parameters member, and an ObjectCollection member (among lots of others).
public class Manager
{
public Parameters {get; private set;}
public ObjectCollection {get; private set;}
...
...
}
I am unable to test the algorithms because everything takes the manager as dependency, and initializing that means I have to initialize everything. So I want to refactor this design.
Parameters has more than 100 fields in it, the values control the different algorithms. The ObjectCollection has the entities required for the overall execution of the engine, stored by Id, by Name, etc.
The following are the approaches I've though of, but not satisfied with:
Pass Parameters and ObjectCollection (or IParameters and IObjectCollection) instead of the Manager, but I don't think this solves any issue. I wouldn't know which of the parameters the algorithms would depend on.
Splitting the parameters class to smaller ones also is difficult as one parameter may affect many algorithms, so a logical separation is difficult. Plus the dependencies for each algorithm may end up to be many.
A singleton pattern like is usually done for a Logger, but that too is not testable.
Some of the parameters control the algorithm logic, some of the parameters are just required for the algorithm. I'm thinking of making each algorithm a separate class implementing an interface, and at the application start, deciding which algorithm to instantiate based on the parameter. I might end up splitting the current set of algorithm classes to many more, and I'm afraid I'll end up complicating it more and losing the structure of the algorithms.
Is there any standard way to deal with this, or is just splitting big classes to smaller ones and passing dependencies by constructor the only general advice?
In order to allow yourself to make small steps I'd start with a single algorithm and identify the parameters it requires. These can then be exposed in an interface so...
public interface IAmTheParametersForAlgorithm1
{
int OneThing {get;}
int AnotherThing {get;}
}
Then you can alter Manager so that it implements that interface and as in #marcel's answer expose those parameters directly on Manager.
Now you can test Algorithm1 with a very small mock or self-shunt because you don't need to initialise a gigantic Manager in order to run your test. And Algorithm1 no longer knows it takes a Manager object.
public Manager : IAmTheParametersForAlgorithm1 {}
public class Algorithm1
{
public Algorithm1(IAmTheParametersForAlgorithm1 parameters){}
}
Bit by bit you can continue expanding this to each of the sets of parameters and dealing with small, specific interfaces will allow you to identify where different algorithms have common parameters.
public Manager :
IAmTheParametersForAlgorithm1,
IAmTheParametersForAlgorithm2,
IAmTheParametersForAlgorithm3,
IAmTheParametersForAlgorithm4 {}
It also means that as you identify algorithms whose parameters are no longer accessed outside of their interface you can stop injecting Manager into those algorithms, take the parameters out of Manager, and create a new class which only provides those parameters.
This means you can keep your application running the whole time you're making this change if you aren't able to dedicate time to make one gigantic breaking change
For the Parameters, I would go with something like this:
public class Parameters
{
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
public class AlgorithmParameters1
{
private Parameters parameters;
public int MyProperty1 { get { return parameters.MyProperty1; } }
public int MyProperty3 { get { return parameters.MyProperty3; } }
public AlgorithmParameters1(Parameters parameters)
{
this.parameters = parameters;
}
}
public class Algorithm1
{
public void Run(AlgorithmParameters1 parameters)
{
//Access only MyProperty1 and MyProperty3...
}
}
Usage would look like:
var parameters = new Parameters()
{
MyProperty1 = 4,
MyProperty2 = 5,
MyProperty3 = 6,
};
new Algorithm1().Run(new AlgorithmParameters1(parameters));
By the way, I don't see how you could differ between parameters that control an algorithm and are required for it. By control do you mean they are used to make a decision which algorithm to take?

Constructor with too many arguments

We have a Transaction class that's very loaded; so loaded that I originally ended up passing almost 20 argument to the ctor. After extracting a few value objects, there are still 12 arguments left, which I still think is too much.
How would I go at avoiding this? I think it's reasonable the arguments are passed to the constructor since they're all required, and I want to make that explicit. I also like how if I add a property, I can add it to the ctor and let my compiler find the places it broke, instead of having to rely on tests for this per se. I don't think object initializers, or builders do the problem any good. It might become more obvious in the next coming days which arguments belong together, and could be composed though.
public class MyEntity()
{
public MyEntity(ValueType prop2, ValueType prop3, ...)
{
Id = Guid.NewGuid();
Prop2 = prop2;
Prop3 = prop3;
...
}
public Guid Id { get; private set; }
public ValueType Prop2 { get; private set; }
public ValueType Prop3 { get; private set; }
public ...
}
Are you sure that all the parameters are required? The word "required" is deceptive, the compiler may force me to provide a string argument, for example, but it can't force me to provide a value that is not null or empty.
The only way to truly force valid data to be provided is to validate it at the point of use. Sometimes this has to be in the constructor, e.g. a class that wraps something that only has meaning when initialised, like an I/O object. However, it's usually sufficient to allow the calling code to set properties any old way, then validate their values in the method call that requires them.
I'm rambling a bit. My point is, don't get hung up on constructor parameters as the only way to provide initialisation data to a class. They give very little additional compiler protection beyond simple properties.
How about encapsulating the parameters in a structure, and passing the structure in?
public struct ParamsStruct
{
Type1 param1;
Type2 param2;
...
}
public void Method(ParamsStruct p)
{
...
}
public void Main(String[] args)
{
ParamsStruct p;
p.param1 = ...
p.param2 = ...
Method(p);
}
When you output the full transaction details in a user or system interface, you will need all the parts. This is unlikely to help you find a split.
But, have a look at your internal processing - are there situations where you use only a subset of the fields on the transaction? Are there places where you pass in a Transaction, but only use 4 of the fields? If you literally always use all fields, then keep them in one object.
In the case of a banking transaction, I would consider a split along these lines:-
Where the money came from
Where the money went to
How the money was moved - which payment instrument or facility was used
Why the money was moved - reference numbers, etc
Amount and currency
Date
Status of the transaction
(Obviously this depends on your exact domain).
public class MyEntity()
{
public ValueType Prop1 { get; set; }
public ValueType Prop2 { get; set; }
// And so on...
public MyEntity()
{
Id = Guid.NewGuid();
}
}
Then:
MyEntity entity = new MyEntity();
entity.Prop1 = prop1;
entity.Prop2 = prop2;
// And so on...
You can eventually consider two different design approaches:
The
essence
pattern.
The fluent
interface
pattern.

How can I avoid ref parameters?

I have a method that has 2 ref parameters:
public void ReplaceSomething(ref int code, ref string name)
{
...
}
I want to avoid this, as it is not a good design (and scales poorly). What are my options?
I've though about using an anonymous object, but that doesn't seem like a good idea, either.
Object something = new { code = 1, name = "test" };
ReplaceSomething(something);
Are the code and the name closely linked together? If so, consider creating a type to put the two of them together. Then you can return a value of that type.
Alternatively, you might consider returning a Tuple<int, string>.
(In both cases you can accept an input parameter of the same type, of course. As you haven't shown any of your code, it's not really clear whether you use the existing values of the parameters, or whether they could basically be out parameters.)
Why don't you want to use ref arguments? That seems like a perfectly good way to change some caller values.
The other approach would be to implement a return value. Maybe you need to better explain what the problem is?
If these values are tightly coupled and "belong together" you could define a custom class that holds your properties and either return a new instance (assuming its immutable) of that or update its properties:
class Code
{
public int Value {get;set;}
public string Name {get;set;}
}
public Code UpdateCode(Code code)
{
...
}
If you need to return these values, you can either use a tuple
public Tuple<int, string> ReplaceSomething(int code, string name)
{
...
}
Or create your own class-wrapper that holds the values as properties
public Foo ReplaceSomething(int code, string name)
{
var foo = new Foo(){...};
return foo;
}
class Foo
{
public int IntValue{get;set;}
public string StringValue{get;set;}
}
Why would you change it? ref parameters make sense at times, and if this is one of those times - use them. You could introduce a new class that contains that pair of values, which only makes sense if those values come together often.
I say, keep it.
Based on your question, I could be way off. What do you mean by replacing ref? Are you looking to overload?
public void ReplaceSomething(int code, string name)
{
// ...
}
public void ReplaceSomething()
{
return ReplaceSomething(1, "test");
}
Edit:
ok, so you need to return the code and the name what are the calculations that need to be made? Jon Skeet's answer about a tuple could be right, or you might need a POCO that contains the code the name and the replaced
public void ReplaceSomething(int code, string name)
{
var replaced = new Replaced();
replaced.code = code;
replaced.name = name;
var r;
// do some replacement calculations
replaced.replaced = r;
return replaced;
}
public class Replaced {
public string name {get; set;}
public int code {get; set;}
public string replaced {get; set;}
}

What is a "mostly complete" (im)mutability approach for C#? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Since immutability is not fully baked into C# to the degree it is for F#, or fully into the framework (BCL) despite some support in the CLR, what's a fairly complete solution for (im)mutability for C#?
My order of preference is a solution consisting of general patterns/principles compatible with
a single open-source library with few dependencies
a small number of complementary/compatible open-source libraries
something commercial
that
covers Lippert's kinds of immutability
offers decent performance (that's vague I know)
supports serialization
supports cloning/copying (deep/shallow/partial?)
feels natural in scenarios such as DDD, builder patterns, configuration, and threading
provides immutable collections
I'd also like to include patterns you as the community might come up with that don't exactly fit in a framework such as expressing mutability intent through interfaces (where both clients that shouldn't change something and may want to change something can only do so through interfaces, and not the backing class (yes, I know this isn't true immutability, but sufficient):
public interface IX
{
int Y{ get; }
ReadOnlyCollection<string> Z { get; }
IMutableX Clone();
}
public interface IMutableX: IX
{
new int Y{ get; set; }
new ICollection<string> Z{ get; } // or IList<string>
}
// generally no one should get ahold of an X directly
internal class X: IMutableX
{
public int Y{ get; set; }
ICollection<string> IMutableX.Z { get { return z; } }
public ReadOnlyCollection<string> Z
{
get { return new ReadOnlyCollection<string>(z); }
}
public IMutableX Clone()
{
var c = MemberwiseClone();
c.z = new List<string>(z);
return c;
}
private IList<string> z = new List<string>();
}
// ...
public void ContriveExample(IX x)
{
if (x.Y != 3 || x.Z.Count < 10) return;
var c= x.Clone();
c.Y++;
c.Z.Clear();
c.Z.Add("Bye, off to another thread");
// ...
}
Would the better solution be to just use F# where you want true immutability?
Use this T4 template I put together to solve this problem. It should generally suit your needs for whatever kinds of immutable objects you need to create.
There's no need to go with generics or use any interfaces. For my purposes, I do not want my immutable classes to be convertible to one another. Why would you? What common traits should they share that means they should be convertible to one another? Enforcing a code pattern should be the job of a code generator (or better yet, a nice-enough type system to allow you to do define general code patterns, which C# unfortunately does not have).
Here's some example output from the template to illustrate the basic concept at play (nevermind the types used for the properties):
public sealed partial class CommitPartial
{
public CommitID ID { get; private set; }
public TreeID TreeID { get; private set; }
public string Committer { get; private set; }
public DateTimeOffset DateCommitted { get; private set; }
public string Message { get; private set; }
public CommitPartial(Builder b)
{
this.ID = b.ID;
this.TreeID = b.TreeID;
this.Committer = b.Committer;
this.DateCommitted = b.DateCommitted;
this.Message = b.Message;
}
public sealed class Builder
{
public CommitID ID { get; set; }
public TreeID TreeID { get; set; }
public string Committer { get; set; }
public DateTimeOffset DateCommitted { get; set; }
public string Message { get; set; }
public Builder() { }
public Builder(CommitPartial imm)
{
this.ID = imm.ID;
this.TreeID = imm.TreeID;
this.Committer = imm.Committer;
this.DateCommitted = imm.DateCommitted;
this.Message = imm.Message;
}
public Builder(
CommitID pID
,TreeID pTreeID
,string pCommitter
,DateTimeOffset pDateCommitted
,string pMessage
)
{
this.ID = pID;
this.TreeID = pTreeID;
this.Committer = pCommitter;
this.DateCommitted = pDateCommitted;
this.Message = pMessage;
}
}
public static implicit operator CommitPartial(Builder b)
{
return new CommitPartial(b);
}
}
The basic pattern is to have an immutable class with a nested mutable Builder class that is used to construct instances of the immutable class in a mutable way. The only way to set the immutable class's properties is to construct a ImmutableType.Builder class and set that in the normal mutable way and convert that to its containing ImmutableType class with an implicit conversion operator.
You can extend the T4 template to add a default public ctor to the ImmutableType class itself so you can avoid a double allocation if you can set all the properties up-front.
Here's an example usage:
CommitPartial cp = new CommitPartial.Builder() { Message = "Hello", OtherFields = value, ... };
or...
CommitPartial.Builder cpb = new CommitPartial.Builder();
cpb.Message = "Hello";
...
// using the implicit conversion operator:
CommitPartial cp = cpb;
// alternatively, using an explicit cast to invoke the conversion operator:
CommitPartial cp = (CommitPartial)cpb;
Note that the implicit conversion operator from CommitPartial.Builder to CommitPartial is used in the assignment. That's the part that "freezes" the mutable CommitPartial.Builder by constructing a new immutable CommitPartial instance out of it with normal copy semantics.
Personally, I'm not really aware of any third party or previous solutions to this problem, so my apologies if I'm covering old ground. But, if I were going to implement some kind of immutability standard for a project I was working on, I would start with something like this:
public interface ISnaphot<T>
{
T TakeSnapshot();
}
public class Immutable<T> where T : ISnaphot<T>
{
private readonly T _item;
public T Copy { get { return _item.TakeSnapshot(); } }
public Immutable(T item)
{
_item = item.TakeSnapshot();
}
}
This interface would be implemented something like:
public class Customer : ISnaphot<Customer>
{
public string Name { get; set; }
private List<string> _creditCardNumbers = new List<string>();
public List<string> CreditCardNumbers { get { return _creditCardNumbers; } set { _creditCardNumbers = value; } }
public Customer TakeSnapshot()
{
return new Customer() { Name = this.Name, CreditCardNumbers = new List<string>(this.CreditCardNumbers) };
}
}
And client code would be something like:
public void Example()
{
var myCustomer = new Customer() { Name = "Erik";}
var myImmutableCustomer = new Immutable<Customer>(myCustomer);
myCustomer.Name = null;
myCustomer.CreditCardNumbers = null;
//These guys do not throw exceptions
Console.WriteLine(myImmutableCustomer.Copy.Name.Length);
Console.WriteLine("Credit card count: " + myImmutableCustomer.Copy.CreditCardNumbers.Count);
}
The glaring deficiency is that the implementation is only as good as the client of ISnapshot's implementation of TakeSnapshot, but at least it would standardize things and you'd know where to go searching if you had issues related to questionable mutability. The burden would also be on potential implementors to recognize whether or not they could provide snapshot immutability and not implement the interface, if not (i.e. the class returns a reference to a field that does not support any kind of clone/copy and thus cannot be snapshot-ed).
As I said, this is a start—how I'd probably start—certainly not an optimal solution or a finished, polished idea. From here, I'd see how my usage evolved and modify this approach accordingly. But, at least here I'd know that I could define how to make something immutable and write unit tests to assure myself that it was.
I realize that this isn't far removed from just implementing an object copy, but it standardizes copy vis a vis immutability. In a code base, you might see some implementors of ICloneable, some copy constructors, and some explicit copy methods, perhaps even in the same class. Defining something like this tells you that the intention is specifically related to immutability—I want a snapshot as opposed to a duplicate object because I happen to want n more of that object. The Immtuable<T> class also centralizes the relationship between immutability and copies; if you later want to optimize somehow, like caching the snapshot until dirty, you needn't do it in all implementors of copying logic.
If the goal is to have objects which behave as unshared mutable objects, but which can be shared when doing so would improve efficiency, I would suggest having a private, mutable "fundamental data" type. Although anyone holding a reference to objects of this type would be able to mutate it, no such references would ever escape the assembly. All outside manipulations to the data must be done through wrapper objects, each of which holds two references:
UnsharedVersion--Holds the only reference in existence to its internal data object, and is free to modify it
SharedImmutableVersion--Holds a reference to the data object, to which no references exist except in other SharedImmutableVersion fields; such objects may be of a mutable type, but will in practice be immutable because no references will ever be made available to code that would mutate them.
One or both fields may be populated; when both are populated, they should refer to instances with identical data.
If an attempt is made to mutate an object via the wrapper and the UnsharedVersion field is null, a clone of the object in SharedImmutableVersion should be stored in UnsharedVersion. Next, SharedImmutableCVersion should be cleared and the object in UnsharedVersion mutated as desired.
If an attempt is made to clone an object, and SharedImmutableVersion is empty, a clone of the object in UnsharedVersion should be stored into SharedImmutableVersion. Next, a new wrapper should be constructed with its UnsharedVersion field empty and its SharedImmutableVersion field populated with the SharedImmutableVersion from the original.
It multiple clones are made of an object, whether directly or indirectly, and the object hasn't been mutated between the construction of those clones, all clones will refer to the same object instance. Any of those clones may be mutated, however, without affecting the others. Any such mutation would generate a new instance and store it in UnsharedVersion.

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