I just updated my VS2017 and it suggest me now to remove all private fields and just use public properties.
Original code:
private string description = "";
public string Description { get => description; set => description = value; }
Now it suggest I should just use:
public string Description { get; set; } = "";
Am I missing something because I thought it was bad practice based on
https://learn.microsoft.com/en-us/visualstudio/code-quality/ca1051-do-not-declare-visible-instance-fields?view=vs-2017
What would be the correct way or what kind of advantage does one have doing it this or that way?
Both implementations will generate the same underlying intermediate language code. However, the suggested changes will result in more human-readable code.
While the original code is not really difficult to read, it's more "wordy" therefore more effort for the next coder to read later (or yourself 6 months down the road). In order to understand the code with the backing field, you look at the get/set and then at the declared private variable to see what is actually being changed or used. The simplified code is all on one line and therefore requires less effort.
The warning in the CA1051 document refers to having a public variable declared as opposed to a public property. The subtle difference is that the suggested syntax does implement the recommendation because the language allows a shortcut to not expose the underlying variable and still be easily read.
Related
Consider below class being updated in database
public class ProductionLineItem
{
public int Id { get; set; }
public DateTime ProductionDate { get; set; }
public string HandledBy { get; set; }
public DateTime DateToMarket { get; set; }
}
void UpdateProductionRecord(ProductionLineItem existingRecord, ProductionLineItem modifiedRecord)
{
existingRecord.Id = modifiedRecord.Id;
existingRecord.ProductionDate = modifiedRecord.ProductionDate;
existingRecord.HandledBy = modifiedRecord.HandledBy;
existingRecord.DateToMarket = modifiedRecord.DateToMarket;
}
Customer wants to keep a log of all changed properties in dedicated table.
I should be doing something like this:
void UpdateProductionRecordWithLog(ProductionLineItem existingRecord, ProductionLineItem modifiedRecord)
{
existingRecord.Id = modifiedRecord.Id;
if (existingRecord.ProductionDate != modifiedRecord.ProductionDate)
{
existingRecord.ProductionDate = modifiedRecord.ProductionDate;
//Log: productionDate update form xyz to abc
}
if (existingRecord.HandledBy != modifiedRecord.HandledBy)
{
existingRecord.HandledBy = modifiedRecord.HandledBy;
//Log: HandledBy updated from Mr. John to Mr. Smith
}
if (existingRecord.DateToMarket != modifiedRecord.DateToMarket)
{
existingRecord.DateToMarket = modifiedRecord.DateToMarket;
//Log: DateToMarket updated form 2013 to 2014
}
}
For small number of properties it should be fine, but if properties goes beyond 15-20. I believe this would not be best way to do it.
Can I make my code more clean? I am open to use any framework like AutoMapper or so, If needed.
There are multiple elegant solutions to your problem, some of those include:
You could use Aspect Oriented Programming (AOP, for frameworks see this answer) to capture every modification to a property. You could save those changes for later retrival or invoke events which are then logged.
You could put Reflection (e.g. PropertyInfo) to good use here and iterate over all properties and compare the current value. This will spare you from writing all properties by hand.
Reflection and Attributes in conjunction with the Properties which are needed to be logged will work too. Using Attributes as a kind of post-it note on those properties which are important to be logged.
Be aware that Reflection might impose some performance penalities.
Do you use Entity Framework? It supports INotifypropertychanged, which could be used:
How to raise an event on Property Change?
If not, your classes could implement INotifyPropertyChanged() themselves - while not great (you have to write geteers / setters explicitly), it provides a better decoupling than invoking a loggin facility in the Properties directly (what if, if your logging is not available).
I would be worried about performance issues, so I might store logs and only write once in a while...
Well first you've done more than the requirement, in that you are only changing Existing item's properties if they are different.
Adding some new method to your class e.g. LogDifferences(ProductLineItem old, ProductLineItem new) and calling it from UpdateProductionItem would be good.
Personally I'd being going back to the Customer and saying what are you really trying to do and why, what they asked for smacks more of solution than requirement.
E.g. just log old record new record, like a DB transaction log. Do the an analysis of what changed when it's required.
One last possiblilty, that admittedly might cause more problems than it solves, is storing the values of the properties in say a Dictionary<String,dynamic> instead of discrete members.
Then logging changes based on Existing["ChangedToMarket"] = Modified["ChangedToMarket"] is fairly trival.
You know how you can have a property that automatically generates a backing field? Like if I go:
public String SomeProperty {get; set;}
I know that if I want to add code to that property I have to create the backing field as so:
public string someProperty = string.Empty;
public string SomeProperty
{
get { return someProperty; }
set
{
someProperty = value;
DoSomething();
}
}
Basically, what I want to know is... is there any way to do this but without having to create the backing field? For example I could use it to trigger some kind of event that occurs when a property is set. I'm looking for something like this:
public string SomeProperty
{
get;
set { this.OnSomeEvent; }
}
But I know that'll cause a compile error because get needs do declare a body if set does.
I've researched and I cant find anything, but I thought I'd check to see if anyone knew.
I guess what I'm really after is some way to trigger an event when a property is changed but without having to add all that extra clutter. Any suggestions?
Simple answer is no, you can't have it both ways. From .NET Docs:
In C# 3.0 and later, auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors.
There are not any solutions for this built into the framework, and you cannot modify existing types via reflection (in order to add the logic at runtime). The only way to accomplish this seems to be at compile time.
There is a product http://www.postsharp.net/ that can accomplish this (intercept property/method calls), and there does appear to be a free edition.
The field keyword might be added to C#, see https://github.com/dotnet/csharplang/issues/140, which removes "when no additional logic" requirement for auto properties.
It didn't make it into C# 10 nor 11, but latest comment from compiler team says C# version 12 might have it. They release yearly, so that would be Nov 2023.
I'm trying to port a years old MS Access app with spaghetti VBA code to C# and OOP, and I'm struggling to find the best way to put domain logic in my domain classes.
I'll use a Country class as a simple example. It has three properties with different business rules:
CountryCode can't be changed anymore once the country is created, because that would cause issues with a 3rd party app that uses the countries
CountryName can be changed anytime, without any underlying logic or business rules
IsoCode can be changed anytime, but must be exactly 2 characters long
(IsoCode has actually more rules, but in this example let's just assume that "must be exactly 2 characters" is the only rule, for the sake of simplicity)
I created two slightly different versions of the class.
I'm quite inexperienced in object-oriented programming, so I need help deciding:
does it matter which approach I use?
does one of them (or both) have issues that I don't see?
is there a different way that's even better?
Both of my approaches look good to me now, but I don't know if maybe they will cause problems later (the app in question is ten years old, and will probably live on for a long time).
Version 1:
public class Country1
{
public string CountryCode { get; private set; }
public string CountryName { get; set; }
public string IsoCode { get; private set; }
public Country1(string countryCode, string countryName, string isoCode)
{
this.CountryCode = countryCode;
this.CountryName = countryName;
SetIsoCode(isoCode);
}
public void SetIsoCode(string isoCode)
{
if (isoCode.Length != 2)
{
throw new ArgumentException("must be exactly 2 characters!");
}
this.IsoCode = isoCode;
}
}
Version 2:
public class Country2
{
public Country2(string countryCode, string countryName, string isoCode)
{
this.countrycode = countryCode;
this.CountryName = countryName;
this.isocode = isoCode;
}
private readonly string countrycode;
private string isocode;
public string CountryCode
{
get { return this.countrycode; }
}
public string CountryName { get; set; }
public string IsoCode
{
get { return this.isocode; }
set
{
if (value.Length != 2)
{
throw new ArgumentException("must be exactly 2 characters!");
}
this.isocode = value;
}
}
}
Some more background about why I'm asking this and what I want to know:
I have read lots of different opinions about the "right OOP way".
Some say that you shouldn't expose getters and setters at all. I understand why this is a bad idea with setters, that's why CountryCode can only be set from the constructor.
Some say that instead of using any getters and setters, you should use GetXXX and SetXXX methods. I can see that this makes sense in some cases (for example, a SetXXX method with several parameters when you have several values that need to be set together).
But often there are simple values like the CountryName in my example, which is a "dumb" value without any logic. When I have ten of these things in one class, I don't want to create GetXXX and SetXXX methods for each of them.
Then there's stuff like the IsoCode, which has no connection to any of the other properties either (so no need to use a SetXXX method to set it together with another property). But it contains some validation, so I could either make a SetXXX method, or just do the validation (and throw an exception when something is wrong) in the setter.
Is throwing an exception even the best way to notify the caller of an error? Some say it's fine, and some say that you should throw exceptions only for "exceptional" cases.
IMO it's not really exceptional when someone enters an invalid ISO code, but how else should I get the information that an error occured (including a human readable error message!!) to the client? Is it better to use a response object with an error code and a ErrorMessage string property?
Personally I don't think there is much difference between the property and method implementation. I have a preference for using properties when the values can be set independently. I use setter methods to force more than one value to be provided to your model at the same time when the values depend on each other in some way (e.g. you are setting integers x and y and y cannot be larger than x).
It makes a lot of sense to have simple validation logic (e.g. required fields, fields lengths) in your view-model because this allows you to tie the validation more closely to the user interface (e.g. you could highlight the field that was invalid after it had been filled in).
For WPF Validation see: http://www.codeproject.com/Articles/97564/Attributes-based-Validation-in-a-WPF-MVVM-Applicat
For MVC Validation see: http://www.codeproject.com/Articles/249452/ASP-NET-MVC3-Validation-Basic
I'd strongly recommend this article by Eric Lippert about what kind of condition makes a good candidate for throwing/catching an exception:
http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx
I tend to use properties for single value changes and SetXXX methods rarely when I have some rule that involve more than one value that must be set at a time too (just like Andy Skirrow said).
SetXXX methods for everything are a common "Javaish" convention (althrough its used in many languages that don't have setters and getters like C#).
People try to force some good practices they learned for some language into every language they can, even if it did not fit necessarily well or the language have better alternatives for that.
Try not to be an "OOP maniac". This will only cause you pain in the head. OOP is not a religion (and even religion should not have fanatics IMHO, but this is another story).
Back to the point
The two approaches makes no functional difference and will not cause any harm in the future. Take the way you fill its more readable and pleasant to code. This will count much more than "the correct OOP way", cause many people have its own definition for the "better way" of doing things.
Validation
If you are using some structural or architectural pattern like MVC, you can use Data Annotation Attributes to enforce validation and, depending on the framework, use it to enforce client side validation as well.
See #Andy Skirrows's answer for links.
I've got a fairly large VB.NET project that was built by a former employee. He got most of it working, but not all of it.
It has been running like this for 2 years, I know. Perhaps 3.
Now, Management is pushing to get this project revived and finish up what was never done.
The project has been assigned to me, and I have been given a month to get up to speed on it.
I am re-writing it in C#, because my coding is stronger in that language.
One of the good ideas he used was to structure the class so that they mimicked the database tables:
table name becomes class name
column names become property names
column datatypes become property datatypes
Here is one small example:
Public Class Acct_Code
Private _Acct_Code_ID As String = String.Empty
Private _Acct_Code As String = String.Empty
Public Property Acct_Code_ID() As String
Get
Return _Acct_Code_ID
End Get
Set(ByVal value As String)
_Acct_Code_ID = value
End Set
End Property
Public Property Acct_Code() As String
Get
Return _Acct_Code
End Get
Set(ByVal value As String)
_Acct_Code = value
End Set
End Property
End Class
Currently, I cannot put this VB code in C# because of Error CS0542 that says:
Error Message
'user-defined type' : member names cannot be the same as their enclosing type
A name was used more than once in the same construct. This error might be caused by inadvertently putting a return type on a constructor.
I understand either the class or the property should be renamed; however, I would like to get this project working piece at a time instead of being over here creating code that will not work at all.
Does anyone know of a way to work around this compiler error - just temporarily until I get the project built?
I know there are ways to ignore warnings and ignore exceptions, but I don't know a way to ignore a compiler error.
To work around the compiler error, just split your class into a base class and a derived class and then move the offending members into the base class.
class A
{
public string B { get; set; } // <-- This compiles just right!
}
class B : A
{
}
You can't ignore a violation of the rules of the language. You must fix the names.
You may well want to try to fix the names in VB before porting, as then you can have a working codebase at all times... which will allow you to take advantage of refactoring. Then when you're sure that all the member names are different from the type names, you can port to C#.
As an aside, when you port that code you should take advantage of automatically implemented properties, leaving:
public class Account
{
public string Id { get; set; }
public string Code { get; set; }
}
(Then try to move away from allowing objects to mutate in all possible ways... that's a different matter :)
I've got a typical C# automatic property. How can I apply WebUtility.HtmlDecode() when I've only got a get; set;?
UPDATE:
Ok, dumb mistake of the day. I had a weird issue where my web.config db connection string was pointed to the right server but for some reason since I had 2 instances (one sql 2008 and 2012) it was still picking up the instance of that DB in 2008 which had the encoding still there. I had fixed the encoding issue by just decoding the Title via a unit test I created in the 2012 DB which in this case this whole fing post was unecessary in stack because the ultimate problem was it was reading from the old DB (messing me up).
Anyway I had already fixed this, finally got rid of the 2008 copy and now it's reading it fine after my fix:
[Test]
public void CleanAllPostEntries_DecodeHTML_DecodeWasSuccessful()
{
// Arrange
// Act
IEnumerable<Entry> posts = PostCRUD.GetAllPosts();
foreach (Entry post in posts)
{
post.Title = WebUtility.HtmlDecode(post.Title);
post.Body = WebUtility.HtmlDecode(post.Body);
post.MetaTitle = WebUtility.HtmlDecode(post.MetaTitle);
PostCRUD.UpdatePost(post);
//System.Diagnostics.Debug.WriteLine("id: " + post.Id);
//System.Diagnostics.Debug.WriteLine("title: " + WebUtility.HtmlDecode(post.Title));
//System.Diagnostics.Debug.WriteLine("body: " + WebUtility.HtmlDecode(post.Body));
}
//Assert
// TODO: add asserts
}
So I don't think I need the decode afterall..I already did it!
you can't, I think. The only way to do is to have a separate method that formats the value and assign it to the property, ex
private string SamplePropery {get; set;}
private string FormatMethod(string value) {}
private void SampleExecute()
{
// format and set to property
SampleProperty = FormatMethod("hello world");
// get property and format the value
string _value = FormatMethod(SampleProperty);
}
The value of a property shouldn't change once set. It's supposed to return the same value you set. That's why it's called a property. Call HtmlDecode before you set the property value.
Should other people work with your classes and not have access to your source they wouldn't imagine you're doing any kind of processing when setting the property value.
You really don't want to do HTML encoding/decoding via properties, although you could if you wanted to. There are several problems with this:
You'll be taking that encoding/decoding hit on every single access of the property, be it reading or writing.
The HTML encode/decode is a "lossy" conversion and you only want to do it exactly once per string; you don't want to be constantly encoding and decoding and re-encoding the same string when you're tossing it around on multiple properties, you'll start to lose information that way.
The HTML encoding of the content is not a property of the object you're storing it with, it is a property of the content itself.
What you really want to do is use a stronger type that represents the HTML-encoded string.
The .NET 4.0 framework includes a System.Web.HtmlString type which you should use for this purpose. In fact, use the System.Web.IHtmlString interface if you wish to remain general.
You can't do it automatically with the magic getters and setters. You need to create your own private property and use it as the backing store for your public properties.
Example:
private string _Item;
public string Item
{
get
{
return _Item;
}
set
{
_Item = WebUtility.HtmlDecode(value);
}
}
However, other answers to this question are correct that this is probably a bad idea. For example, if your code is ever used outside of an HTML application, you will have to HTML-encode all text before you set this property.