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.
Related
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.
Supposing I have an Album class :
public class Album
{
public string Name {get; set;}
public string Artist {get; set;}
public int Year {get; set;}
public Album()
{ }
public Album(string name, string artist, int year)
{
this.Name = name;
this.Artist = artist;
this.Year = year;
}
}
When I want to assign data to an object of type Album, what is the difference between the next 2 approaches :
Via Constructor
var albumData = new Album("Albumius", "Artistus", 2013);
or when instantiating
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
Both approaches call a constructor, they just call different ones. This code:
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
is syntactic shorthand for this equivalent code:
var albumData = new Album();
albumData.Name = "Albumius";
albumData.Artist = "Artistus";
albumData.Year = 2013;
The two are almost identical after compilation (close enough for nearly all intents and purposes). So if the parameterless constructor wasn't public:
public Album() { }
then you wouldn't be able to use the object initializer at all anyway. So the main question isn't which to use when initializing the object, but which constructor(s) the object exposes in the first place. If the object exposes two constructors (like the one in your example), then one can assume that both ways are equally valid for constructing an object.
Sometimes objects don't expose parameterless constructors because they require certain values for construction. Though in cases like that you can still use the initializer syntax for other values. For example, suppose you have these constructors on your object:
private Album() { }
public Album(string name)
{
this.Name = name;
}
Since the parameterless constructor is private, you can't use that. But you can use the other one and still make use of the initializer syntax:
var albumData = new Album("Albumius")
{
Artist = "Artistus",
Year = 2013
};
The post-compilation result would then be identical to:
var albumData = new Album("Albumius");
albumData.Artist = "Artistus";
albumData.Year = 2013;
Object initializers are cool because they allow you to set up a class inline. The tradeoff is that your class cannot be immutable. Consider:
public class Album
{
// Note that we make the setter 'private'
public string Name { get; private set; }
public string Artist { get; private set; }
public int Year { get; private set; }
public Album(string name, string artist, int year)
{
this.Name = name;
this.Artist = artist;
this.Year = year;
}
}
If the class is defined this way, it means that there isn't really an easy way to modify the contents of the class after it has been constructed. Immutability has benefits. When something is immutable, it is MUCH easier to determine that it's correct. After all, if it can't be modified after construction, then there is no way for it to ever be 'wrong' (once you've determined that it's structure is correct). When you create anonymous classes, such as:
new {
Name = "Some Name",
Artist = "Some Artist",
Year = 1994
};
the compiler will automatically create an immutable class (that is, anonymous classes cannot be modified after construction), because immutability is just that useful. Most C++/Java style guides often encourage making members const(C++) or final (Java) for just this reason. Bigger applications are just much easier to verify when there are fewer moving parts.
That all being said, there are situations when you want to be able quickly modify the structure of your class. Let's say I have a tool that I want to set up:
public void Configure(ConfigurationSetup setup);
and I have a class that has a number of members such as:
class ConfigurationSetup {
public String Name { get; set; }
public String Location { get; set; }
public Int32 Size { get; set; }
public DateTime Time { get; set; }
// ... and some other configuration stuff...
}
Using object initializer syntax is useful when I want to configure some combination of properties, but not neccesarily all of them at once. For example if I just want to configure the Name and Location, I can just do:
ConfigurationSetup setup = new ConfigurationSetup {
Name = "Some Name",
Location = "San Jose"
};
and this allows me to set up some combination without having to define a new constructor for every possibly permutation.
On the whole, I would argue that making your classes immutable will save you a great deal of development time in the long run, but having object initializer syntax makes setting up certain configuration permutations much easier.
Second approach is object initializer in C#
Object initializers let you assign values to any accessible fields or
properties of an object at creation time without having to
explicitly invoke a constructor.
The first approach
var albumData = new Album("Albumius", "Artistus", 2013);
explicitly calls the constructor, whereas in second approach constructor call is implicit. With object initializer you can leave out some properties as well. Like:
var albumData = new Album
{
Name = "Albumius",
};
Object initializer would translate into something like:
var albumData;
var temp = new Album();
temp.Name = "Albumius";
temp.Artist = "Artistus";
temp.Year = 2013;
albumData = temp;
Why it uses a temporary object (in debug mode) is answered here by Jon Skeet.
As far as advantages for both approaches are concerned, IMO, object initializer would be easier to use specially if you don't want to initialize all the fields. As far as performance difference is concerned, I don't think there would any since object initializer calls the parameter less constructor and then assign the properties. Even if there is going to be performance difference it should be negligible.
This might be a bit of a noob question, but I need to ask it anyway. Consider the following two classes
public class Book{
public string Title;
public string Author;
public string ISBN;
public DateTime Published;
public string Description;
public string Genre;
public float Price
public int Pages;
public Book(){
}
}
public class BookStub{
public string Title;
public string Author;
public BookStub(){
}
}
If I create an instance of each class in the following way
Book a = new Book{
Title = "Do Androids Dream of Electric Sheep?",
Author = "Philip K. Dick"
};
BookStub b = new BookStub{
Title = "Do Androids Dream of Electric Sheep?",
Author = "Philip K. Dick"
};
Do both of these instances take up the same amount of memory? Or does the first one take up more?
Instances of the Book class will consume more memory than instances of the BookStub class because the memory required for all member variables is allocated when an object is first created.
This is necessary because at any time you could write
a.Price = 12.74F;
to set the value of the Price field. If the memory had not been allocated, this code would fail.
Such failure is not possible for object b of type BookStub, because it has no Price field. The compiler would easily detect that error.
So, to answer your question explicitly: yes, unassigned properties still consume memory for each instance of a class. They are simply initialized automatically to their default values.
Note, however, that this is only the case for member variables that must exist for each instance of an object. Both static fields and all types of methods (instance or static) are associated with the class itself and do not consume any additional memory each time a new instance is created. So feel free to add additional methods and static fields without worrying about increasing your memory footprint.
Class Book will consume more memory than BookStub. It doesn't matter that you don't assign to the properties; they still get initialized to the appropriate default values for their types, and those values have to be stored somewhere.
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.
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;
}
}