I 've just started writing a little app. I made things work now I am in plan to do everything what is needed better. I've discovered one mistake.
I have a class with static field which is an arraylist and its access is public.
Other classes uses it and I m wondering what would be the best option to get acces from other classes to this field.
First what I have in mind its just getter returning this list.
But I have no other ideas what could beanother option I decided to ask.
Greetings,
Betty
It can be done in a different ways, this is one of them:
public class TestService
{
private static readonly List<string> list = new List<string>();
public IEnumerable<string> List
{
get { return list; }
}
//list manipulation methods...
}
Basically, you should prevent manipulation (i.e. add/update/remove items) on that list from outside of the class. Mainly because that class should be only responsible for direct list manipulation.
So, that's the reason behind IEnumerable<string> type. Do not misuse List<string> casting on this property!
Now when you are sure that list can't be directly manipulated from the outside of the class, you should expose public methods inside TestService class. Each method should only have one responsibility and reason to change (SRP), in other words, you should have separate methods for adding, updating and removing items.
Related
I have a public property of type List<> in class MyClass. It is public because code outside of MyClass (including the XAML bindings) need to be able to access and change the data. However, the one thing that elements outside of MyClass should NOT be able to do is call the Add() method. The only way to add a new method to the list should be through the MyClass.MyListAdder() method.
Is there a way to accomplish this?
You can try switching to ReadOnlyCollection<T>. It has slightly different API than List<T> but might be good enough for your needs.
This is probably what you're looking for:
List<object> someList = new List<object>();
public ReadOnlyCollection<object> SomeList
{
get
{
return someList.AsReadOnly();
}
}
I'm trying to get the idea, what would be the best way to publish a Readonly List of objects as a public method?
From Eric Lippert's Blog, Arrays are kinda bad, because someone could easily add a new Entry. So one would have to pass a new Array every time the method is called.
He suggests, to pass IEnumerable<T>, since this is per definition read only (no add, remove methods), which I practiced for quite sometime.
But in our new project, people even started to create Arrays of these IEnumerables, because they don't know the DataSource behind, so they get a : Handling warning for possible multiple enumeration of IEnumerable
I'm interested in a technical approach, how one would solve this puzzle. The only solution I came up so far would be to use a IReadOnlyCollection, but this would be way more explicit than an IEnumerable.
What is best practice to publish such lists, which shouldn't be changed, but should be declared as In-Memory Lists?
Usually - and since a while - this solved using immutable collections.
Your public properties should be, for example, of type IImmutableList<T>, IImmutableHashSet<T> and so on.
Any IEnumerable<T> can be converted to an immutable collection:
someEnumerable.ToImmutableList();
someEnumerable.ToImmutableHashSet();
... and so on.
This way you can work with private properties using mutable collections and provide a public surface of immutable collections only.
For example:
public class A
{
private List<string> StringListInternal { get; set; } = new List<string>();
public IImmutableList<string> StringList => StringListInternal.ToImmutableList();
}
There's also an alternate approach using interfaces:
public interface IReadOnlyA
{
IImmutableList<string> StringList { get; }
}
public class A : IReadOnlyA
{
public List<string> StringList { get; set; } = new List<string>();
IImmutableList<string> IReadOnlyA.StringList => StringList.ToImmutableList();
}
Check that IReadOnlyA has been explicitly-implemented, thus both mutable and immutable StringList properties can co-exist as part of the same class.
When you want to expose an immutable A, then you return your A objects upcasted to IReadOnlyA and upper layers won't be able to mutate the whole StringList in the sample above:
public IReadOnlyA DoStuff()
{
return new A();
}
IReadOnlyA a = DoStuff();
// OK! IReadOnly.StringList is IImmutableList<string>
IImmutableList<string> stringList = a.StringList;
Avoiding converting the mutable list to immutable list every time
It should be a possible solution to avoid converting the source list into immutable list each time immutable one is accessed.
Equatable members
If type of items overrides Object.Equals and GetHashCode, and optionally implements IEquatable<T>, then both public immutable list property access may look as follows:
public class A : IReadOnlyA
{
private IImmutableList<string> _immutableStringList;
public List<string> StringList { get; set; } = new List<string>();
IImmutableList<string> IReadOnlyA.StringList
{
get
{
// An intersection will verify that the entire immutable list
// contains the exact same elements and count of mutable list
if(_immutableStringList.Intersect(StringList).Count == StringList.Count)
return _immutableStringList;
else
{
// the intersection demonstrated that mutable and
// immutable list have different counts, thus, a new
// immutable list must be created again
_immutableStringList = StringList.ToImmutableList();
return _immutableStringList;
}
}
}
}
I do not think immutable is the way to go
int[] source = new int[10000000];//uses 40MB of memory
var imm1 = source.ToImmutableArray();//uses another 40MB
var imm2 = source.ToImmutableArray();//uses another 40MB
List behaves the same way. If I want to make full copy every time, I do not have to care about what user does with that array. Making it immutable does not protect content of objects in the collection either, they can be changed freely. #HansPassant suggestion seems to be best
public class A
{
protected List<int> list = new List<int>(Enumerable.Range(1, 10000000));
public IReadOnlyList<int> GetList
{
get { return list; }
}
}
For a collection that you don't intend to modify, IEnumerable<T> is still probably the safest option, plus it allows any collection type to be pased in, not just arrays. The reason for that warning is because of the possibility that the IEnumerable represents a query that uses deferred execution, meaning that a potentially expensive operation could be executed multiple times.
Note that there's not an interface that distinguish in-memory collections versus potentially deferred-execution wrappers. That question has been asked before.
The fix for that is do not enumerate the source multiple times. If the code needs perform multiple iteartions (which may be legitimate) then hydrate the collection to a List<T> before iterating.
IEnumerable is a read-only interface which hides implementation from user. Some can argue, that user may cast IEnumerable to list and add new items, but that means two things:
User violates provided API
You can't stop user from reflection usage
IEnumerable describes behavior, while List is an implementation of that behavior. When you use IEnumerable, you give the compiler a chance to defer work until later, possibly optimizing along the way. If you use ToList() you force the compiler to prepare the results right away.
I use IEnumerable Whenever working with LINQ expressions, because by only specifying the behavior, I give LINQ a chance to defer evaluation and possibly optimize the program.
To prevent any modifications to the List<T> object, expose it only through the ReadOnlyCollection<T> wrapper which does not expose methods that modify the collection. However, if changes are made to the underlying List<T> object, the read-only collection reflects those changes as described in MSDN.
Take a look at The New Read-Only Collections in .NET 4.5 please.
I've been programming for longer than I care to remember, and never had such a requirement to protect a list from getting modified. I'm not saying it's not a possible requirement, I'm just saying it is very rare to need such a requirement. If you have a list circulating around in your app, then most likely you have to fix your design. If you need help with that, let us how you're using the list.
The examples you're giving in your question and comments are not good examples for when to require an immutable or read-only list. Let's discuss them one by one.
You mentioned publishing it as an API. By definition, anything you return from an API is no yours anymore and you shouldn't care how it is used. In fact, once it leaves your API, it is now in the API client's domain, and they can do whatever they want with it. Aside from the fact that you cannot protect it once it is in their domain, you should not dictate how they will use it. More importantly, you should never accept anything as input in your API, even if it is the same list that you returned earlier and you think that you protected. All input MUST be validated appropriately.
Perhaps, you did not really mean API, but more like a DLL library that you share in your projects. Whether it is a DLL or just a class in your project, the same principle applies. When you return something, it is up to the user how to use it. And you should never accept the same thing (list or whatever) back without validation. Similarly, you should never expose an internal member of your class, whether it's a list or a single value. After all, that's the whole idea behind using properties instead of marking the members as public. When you create a property for a single-value member, a copy of the value is returned. Similarly, you should create a property for your list and return a copy, not the list itself.
If you really need a list that is globally accessible, and you want to load it only once, expose it to other classes, protect it against modification, and it is too big to make a copy of it. You can look into some designs like wrapping it in a Singleton and/or make it read-only as per AntonĂn Lejsek's answer. In fact, his answer can be easily converted to a Singleton by marking the constructor as private, thanks to the simplified Singleton implementation in C#.
I am new to C#. Come from the C/C++ environment. My application has a List<Model> which is required all over the place, by different classes. The problem is that a copy will not do because this statement:
dataGrid.ItemsSource = myModelList;
requires the original by address. I tried changing some arguments around and passing that particular variable as ref but as soon as it is assigned with an equal sign, I end up with a copy. Correct?
You could make it a singleton.
However a concrete List needed all over the place would make me have a serious think about my design.
At the very least you should consider writing a class to control access to the list (add, remove, clear etc), and making that "global", otherwise you are going to be in deep in the brown stuff, until it hits the fan.
Create a Public Class and have the content you wish to pass declared static within the class. Then just access it as NameOfClass.NameOfMethod()
public class NameOfClass
{
public static RETURNTYPE NameOfMethod()
{
// Your Code
}
}
You can create a public class for it with a public static List inside it. That one you then can access everywhere.
eg
public class FakeGlobal
{
public static List<Model> MyModelList = new List<Model>();
}
or even make it a property with getter/setter.
public class ScheduleRatesController
{
protected CoreDataManager dataManager;
public ScheduleRatesController()
{
dataManager = new CoreDataManager();
}
// testing
public ScheduleRatesController(CoreDataManager manager)
{
dataManager = manager;
}
public virtual void GetTranQuotesToFillRatesAndPayments(ref List<int> ids)
{
ids.AddRange(new List<int>());
}
}
So to give you guys some background, we're splitting one DB query into a bunch of different ones, and we want subclasses to basically each take on a DB call for their GetTranQuotesToFillRatesAndPayments() method that represents it's specific query.
What you see above is the base class I have. I made those two methods virtual as I plan on having subclasses override them to perform their own stuff. So one could be like:
public override void GetTranQuotesToFillRatesAndPayments(ref List<int> ids)
{
ids.AddRange(dataManager.GetLoanTranQuotes());
}
and etc. My question is, is this the best/cleanest way to perform a pattern like this?
The code that calls this is going to contain a huge list of filtered id's, that it's going to need to fill by calling each classes call to GetTranQuotesToFillRatesAndPayments(). Let me know if this doesn't make sense. I'm kind of getting turned off by the fact that I'm going to need to call the same method like 6 times, each on a different class. I think that might be messy in itself even though the goal of it was to make it clean. I don't want to have something like this on the calling side:
List<int> ids = new List<int>();
ScheduleRatesController controller = new LoanController();
controller.GetTranQuotesToFillRatesAndPayments(ref ids);
controller = new TradeController();
controller.GetTranQuotesToFillRatesAndPayments(ref ids);
etc.
Let me know if you need any more background or info.
Thanks.
Several design remarks:
Using the ref keyword usually indicates design problems and should be avoided. There is no need to pass a reference value using the ref keyword (any List<T> is always passed by reference). Your program would work equally without it.
A better idea than passing your list to the method would be to return your data from the method, and allow callers to decide what to do with it. Maybe you will only want to find a single value at some other place in your program, and creating a new list is an overkill. Also, you should try to add as little functionality as possible to each class (Single Responsibility Principle), and your class is right now responsible for fetching the data and deciding how it should be stored.
Naming: your method name is really complex. Also, the name "controller" doesn't usually represent an object responsible for fetching data.
On the other hand, you have a CoreDataManager class (btw, Manager is a bad suffix for any class), which appears to contain a bunch of methods which return various data. What is the need for ScheduleRatesController then? Does it only copy this to a list?
Business logic should be separated from your Data access layer. You should consider using Repository pattern, or similar (check this answer, for example), to ensure that your data class only fetches the data from the DB.
If you have several classes which need to fulfill a certain contract, start by creating the interface which they need to implement. Don't think about reusing code at this time. Your code, for example, forces all subclasses to use the CoreDataManager, while one day it may turn out that a certain "controller" might need to be composed of different objects.
Use a List<Func<List<int>,List<int>>>. Which is basically a list of functions with the following type signature:
List<int> MyFunc(List<int> foo);
You can then pass the list of functions to a method that works like the following:
public List<int> GetAllIds(List<Func<List<int>,List<int>>> functionList) {
var listOfIds = new List<int>();
foreach(var f in functionList) {
listOfIds = f(listOfIds);
}
return listOfIds;
}
You can use lambdas to compose functionList like so:
functionList.Add(list => {
list.AddRange(dataManager.GetLoanTranQuotes());
return list;
});
Now you do not have to depend on any specific inheritance hierarchy. You can use function composition to produce the whole list.
I'm looking for an opinion on something. Consider the following code from a class called SomeApiObject:
// Property with private setter
public IList<string> SomeList
{
get;
private set;
}
// Constructor
public SomeApiObject()
{
SomeList = new List<string>();
}
With this setup, users of the class SomeApiObject cannot reassign the SomeList property, but what they can do is to manipulate the existing list by using methods such as Add(), Remove(), and Clear().
The upside of this pattern is that the property is guaranteed to never be null, which can be a very convenient assumption to make as a user is working with the API, since it means the user can always iterate over the list, get the list's size, or add to it without ever having to check for null.
I see a few downsides. For one, it's not necessarily obvious to a user that the list is intended to be writable by manipulating its contents. For another, I could envision situations where manipulating the list is less convenient syntactically or possibly worse in performance than assigning a new list.
I'm on the fence with this one, and I'm seeking opinions.
Are the potential downsides just too obnoxious for a user of the API?
Is the guarantee of never being null as nice a feature as I think it is?
EDIT:
I'm already convinced of the benefits of using some sort of "never null" pattern. What I'm more interested in is for someone to play devil's advocate and show me why having a private setter on a list that's meant to be manipulated might be annoying and/or prohibitive from the perspective of a user of the API.
I released a .NET API wrapper some time ago, and so far a few users have expressed confusion over how to assign values to properties like this one.
Never null is a good design feature. In regards to only exposing lists as read only properties this is put forward as a recommendation in the my favorite guidelines book: http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613
Though a better approach is not to allow external callers to manipulate the state of your object directly and to make the class immutable:
public class MyClass
{
private List<string> _inner = new List<string>();
public IEnumerable<string> Items
{
get { return _inner.GetEnumerator(); }
}
public void AddItem(string item);
{
_inner.Add(item);
}
}
If you want to remove the possibility of users getting a reference to the list then simply manipulating it externally in an unintended manner, then you should change your property to only return an IEnumerable instead.
public IEnumerable<string> SomeList
{
get { return list.GetEnumerator(); }
private set {}
}
This will allow the user to still make use of the collection (also will support linq) and will protect the collection from external manipulation.
One other point to consider is that the question depends on whether the object "owns" the list (composition) or "has" the list (aggregation). If the object owns the list, the setter should be private; if it simply has the list from another object, the setter could possibly be public.
A complication in the composition case (other than the possibility of the list being assigned a null value) is that a public setter causes the class to cede all control over the implementation of the list. Suppose, for instance, you have the implementation:
public IList<string> SomeList
{
get;
private set;
}
public SomeApiObject()
{
SomeList = new List<string>();
}
Now suppose in a subsequent version, you want to use SomeSpecializedList, which implements IList<string>, instead of List<String>. You could easily refactor:
private SomeSpecializedList specializedList;
public IList<string> SomeList
{
get {return specializedList;}
private set {specializedList = value as SomeSpecializedList;}
}
public SomeApiObject()
{
SomeList = new SomeSpecializedList<string>();
}
Only the private implementation has changed; users of the class are unaffected. But if the setter were public, the client could have potentially passed any IList instance into SomeList, and this would be a breaking change.
it depends on the situation. in some cases, it might make sense to be able to have a null list, in other not so much. you have to ask yourself if it makes sense. .net itself does it both ways.
As much as I hate saying this, it really depends on what you're trying to do with your API. If you want to provide the user with a collection that they can work with, then #Matthew's answer is appropriate. If you want to hide the collection or only allow certain actions to be permitted (like Add, Remove, etc.), then you could hide the collection and expose a facade to the collection:
private IList<string> _someList = new List<string>();
public void Add(string item){ _someList.Add(item); }
public string Remove(string item) { return _someList.Remove(item); }
...
Hope this helps.