问题
I have a class property that looks as follows:
public List<Recipe> RecipeList
{
get { return this._recipeList; }
set
{
this._recipeList = value;
OnPropertyChanged("RecipeList");
}
}
In another method I have the following which references the property above.
private void RecipeSearch()
{
this.RecipeList = RecipeManagerService.SearchByUnit(SearchCriteria)
.Where(recipe => recipe.IsApproved == true && !recipe.IsHidden).ToList();
}
Code Analysis is issuing a CA 2227 warning: Change RecipeList to be read-only by removing the setter. Could anyone tell me why?
回答1:
Adding a public setter on a List<T>
object is dangerous. You can eliminate this warning by making your setter private:
public List<Recipe> RecipeList
{
get { return this._recipeList; }
private set
{
this._recipeList = value;
OnPropertyChanged("RecipeList");
}
}
This will still allow your class to change this method, but no external source.
回答2:
I think it's suggesting that usually collection properties themselves shouldn't be mutable - it's more common for the collection to be mutable, and just available via a setter.
It's only a suggestion though :)
In this case you'd use:
RecipeList.Clear();
RecipeList.AddRange(RecipeManagerService
.SearchByUnit(SearchCriteria)
.Where(r => r.IsApproved && !r.IsHidden));
Note that this won't fire the change event though... you might want to use ObservableCollection instead.
This will also mean that anyone can change the contents of the recipe list... do you definitely want that? Another alternative is to expose a ReadOnlyCollection<T>
property or something like that, and only make changes within your own class. It really depends what you're trying to do though.
回答3:
Do you want another instance messing with RecipeList
? Generally, I don't let anything change my collection instances except the instance that owns the collection. You could make it private
.
回答4:
The MSDN description is fairly clear:
A writable collection property allows a user to replace the collection with a completely different collection
It wouldn't be good OO if the client of your class could change the list to be a completely different list of Recipes. That is against encapsulation.
Ensuring the clients just add or remove items is what you probably want to do.
回答5:
I don't think there's anything illegal about the code, but it's common practice to have no public setter for collection type properties. Your private RecipeSearch
method should just set _recipeList
and raise the event, or you could make _recipeList
itself a protected property that handles the event.
回答6:
Allowing the list property to be mutated in two ways (via it's own Add
and Remove
methods and the list instance as a whole) creates an ambiguous interface to those who consume that property. This confuses responsibilities and creates a larger technical debt/maintenance overhead.
Instead, it is often better practise to separate these concerns so that the property provides access to a single instance of the list. If the list instance must be changeable, a separate mechanism for doing so makes it much clearer that the action of interacting with the property and the action of changing which list instance that property points to are distinct.
来源:https://stackoverflow.com/questions/5554566/c-sharp-code-analysis-2227-confusion