I am currently writing an application that builds a connection to some sort of Service, gets Data in the form of a few DataTable objects and then is supposed to show it to the user.
In order to store the Data I get I made a class called DataStorage which has a List<DataTable>. Other classes need to be able to edit this List, for example adding objects that are needed or removing them if the user finds them unnecessary. I also have to be able to clear it, should I need a completely new set of data.
I could give the DataStorage methods for that but since the List<T> already offers these, I see no point in encapsulating it like that. So I made it readonly to ensure nobody tries to assign a new object - or even worse, null - and made the access modifier public.
Is this sort of design acceptable or should I always protect fields from direct access, no matter what?
General speaking you should allways take the most general type to reduce any tight coupling and to provide only those members you actually need access to. Having said this in some situations it might be better to use an ICollection instead which provides access to basic methods such as Add, Remove and Clear.
However making the collection readonly or even better a Get-only property is probably a good idea and nothing can be said against this.
We should be very careful with public which means public - whatever.
Do you let any class behave in such a way?
public class Offender {
...
public void Offend(YourClass value) {
...
// In the middle of my routine I've ruined your class
value.Data.Clear();
value.Data.Add(someStuff);
...
}
}
I suggest restricting full access to Data to trusted classes only:
public class YourClass {
// Approved classes (i.e. from your routine) can write, delete, clear...
internal readonly List<Data> m_Data = new List<Data>();
// All the other can only read
public IReadOnlyList<Data> Data {
get {
return m_Data;
}
}
...
// If you let (in some cases) add, delete, clear to untrusted class
// just add appropriate methods:
public void Add(Data data) {
// Here you can validate the provided data, check conditions, state etc.
}
}
If you want to publish a collection with add/remove capability, it is the best if you override the Collection<T> (or ObservableCollection<T>) class, which is very similar to List<T>, but you can override and thus control the add/remove/replace operations. And yes, you can make it public via a get-only property.
public class MyClass
{
private MyCollection myCollection = new MyCollection();
public IList<MyElement> Collection { get { return myCollection; } }
}
internal class MyCollection: Collection<MyElement>
{
// by overriding InsertItem you can control Add and Insert
protected override InsertItem(int index, MyElement item)
{
if (CheckItem(item))
base.InsertItem(index, item);
throw new ArgumentException("blah");
}
// similarly, you can override RemoveItem to control Remove and RemoveAt,
// and SetItem to control the setting by the indexer (this[])
}
Related
What is a good (object oriented) way of setting a property of a class which implements an interface, when that property doesn't always exist in all classes that implement that same interface?
e.g.
Let's say I have an interface
public interface IDataRepository {
public DataStructure GetData(); // DataStructure is an arbitrary class, doesn't matter for this example
}
Now I also have two classes that inherit from this
public class DatabaseRepository : IDataRepository {
public DataStructure GetData()
{
// get data from database
}
}
and
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; }
public DataStructure GetData() {
// get data from files
}
}
Now my client method doesn't necessarily know what the repository is but here's what I want to do...
private DataStructure ReadData(IDataRepository repository)
{
repository.WorkingFolder = #"C:\Data"; // What is the best way of doing this?
return repository.GetData();
}
obviously the above code won't work and I could do...
if (repository is FileRepository) {
((FileRepository)repository).WorkingFolder = #"C:\Data";
}
or add WorkingFolder as a property of the interface (and therefore all the classes that implement it) even though in most cases it's irrelevant.
but both of these (esp. the first one) seem very inelegant and not very object oriented. What is the oop way of doing this kind of thing?
Edit
The obvious question is if the method doesn't know what repository is, how can it know the correct value for WorkingFolder... But the above is an over-simplification of what I'm trying to do, so let's just say it can find out...
Apparently your ReadData method can't actually accept any type of repository. It is only able to handle a FileRepository. That's what it expects, and that's what it needs to do its job. Given that, that's what it should actually accept as its parameter, rather than an interface that doesn't actually provide a contract that is sufficient for it to do its job.
The entire point of having an interface is so that anyone using that interface can use it without caring what the implementation is. So if you do want to use the interface you need to include enough information in the interface's definition such that it provides every operation that anyone using the interface needs, otherwise you're better off just not using it at all (at least for that specific operation).
As for the specific example given, you should probably just be providing an already configured repository, that has whatever values it needs in order to allow this method to do its work, as a parameter. It doesn't make sense for a method that's reading a value from an arbitrary repository to be configuring that repository at all. That is, if it really is reading something from an arbitrary repository.
As others have said in the comments, you should initialise these properties in the constructor. This is where you know what type you're creating, so you also know what arguments its constructor requires / can set those there.
Once you've initialised the object, you can just pass it around / have anything using that class operate against its interface.
Example:
public void Main(string[] args)
{
var myRepo = new FileRepository(args[0]); //Here's where we set the working directory
var myThing = new Thing();
var data = myThing.ReadData(myRepo);// of course, the current implementation means you could just call `myRepo.GetData()` directly, since ReadData just passes out the same response; but presumably that method adds some additional value..
Console.WriteLine(data.ToString());
}
Supporting Code
public class DatabaseRepository : IDataRepository {
DbConnection connection; //you may want a connection string or something else; going with this type just to illustrate that this constructor uses a different type to the FileRepo's
public DatabaseRepository(DbConnection connection)
{
this.connection = connection;
}
public DataStructure GetData()
{
// get data from database
}
}
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; } //Do you need set? Generally best to keep it constant after initialisation unless there's good reason to change it
public FileRepository (string workingFolder)
{
this.WorkingFolder = workingFolder;
}
public DataStructure GetData() {
// get data from files
}
}
How do I call the code that creates the class
i.e. maybe you've implemented a really basic factory pattern like so, and want to know how to provide arguments:
public class DataRepositoryFactory
{
Type baseType = typeof(IDataRepository);
IDictionary<string, Type> typeMap = new Dictionary<string, Type>() {
{"File", typeof(FileRepository) }
,{"Db", typeof(DatabaseRepository) }
}
public void RegisterType(string typeName, Type type)
{
if (!baseType.IsAssignableFrom(type)) throw new ArgumentException(nameof(type));
typeMap.Add(typeName, type);
}
public IDataRepository GetDataRepository(string typeName)
{
return (IDataRepository)Activator.CreateInstance(typeMap[typeName]);
}
}
(For a more complex example of a factory, see https://web.archive.org/web/20140414013728/http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c).
I.e. in this scenario, when you call the factory you know what type you want, but you're only giving it a string to name/identify that class. You could add a params object[] args to your GetDataRepository method, allowing you to call it like so:
var myRepo = myDataRepositoryFactory.GetDataRepository("File", "c:\somewhere\something.dat");
That's a good approach / is actually what's used on the linked example above. However, it means that your call to this code differs for different types; since if we use variables instead of hardcoded values as in the above example we can't simply do the below, since myRepoType could be set to "Db", whilst "myFilePath" would be a string:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myFilePath);
That's fixable by calling:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myArgs);
i.e. where myArgs is an object[], giving all of the values required in the desired order to initialise the type. The piece to populate object[] with the required values could then take place at the same point at which you decided you wanted the type to be a file repo vs database repo. However, this approach isn't that clean / casting to and from objects stops you from getting help from the compiler.
So how do I improve things?
There are a few options. One is to replace the need to use object[] by instead creating a type to hold your arguments. e.g.
public interface IDataRepositoryConfiguration
{
//nothing required; this is just so we've got a common base class
}
public class FileRepositoryConfiguration: IDataRepositoryConfiguration
{
public string WorkingFolder {get;set;}
}
public class FileRepository : IDataRepository {
public FileRepository (IDataRepositoryConfiguration configuration)
{
var config = configuration as FileRepositoryConfiguration;
if (config == null) throw new ArgumentException(nameof(configuration)); //improve by having different errors for null config vs config of unsupported type
this.WorkingFolder = config.WorkingFolder;
}
//...
}
This still has some issues; i.e. we may pass a DatabaseRepositoryConfiguration as our IRepositoryConfiguration when creating a FileRepository, in which case we'd get the AgumentNullException at runtime; but this does avoid issues should parameters change order, and makes it less of a headache to code / debug.
Could it be further improved?
Dependency Injection offers one solution. This could be used along the lines of the code below (i.e. you create instances of each of your classes, providing the required arguments, and give each instance a name, so that you can later fetch that instantiation. Exactly what that code looks like would depend on the dependency injection library you used:
//setting up your repositories
var container = new Container();
container.Configure(config =>
{
// Register stuff in container, using the StructureMap APIs...
config.For<IDataRepository>().Add(new FileRepository("\\server\share\customers")).Named("customers");
config.For<IDataRepository>().Add(new FileRepository("\\server\share\invoices")).Named("invoices");
config.For<IDataRepository>().Add(new DatabaseRepository(new DbConnection(configurationString))).Named("persist");
config.For<IDataRepository>().Use("persist"); // Optionally set a default
config.Populate(services);
});
//then later when you need to use it...
public DataStructure ImportCustomers(IContainer container)
{
var customerRepo = container.GetInstance<IDataRepository>("customers");
return customerRepo.GetData();
}
I'm sure there are many other approaches, and exactly what approach to use depends on how your program will operate. Hopefully the above is enough to get you past your current problem; but if you find you're still struggling please post a new question with more detail / saying where you're still having issues having considered these points.
If possible, I'd just put the value for that property in the constructor or create a subinterface, like others suggested.
If it's not possible, C# 7.X (don't remember the exact minor version) has a nice code structure for conditional casting:
IDataRepository repo = new FileRepository();
if (repo is FileRepository fileRepo)
{
fileRepo.WorkingFolder = "some dir";
}
However in your case, you should probably rethink your architecture and always pass (or even better always create) a repository object which is ready to be used.
a) Put it into the Inferface definitions. Deal with any "NotImplemented" Exceptions. You always have to expect those with Interfaces anyway.
For example, IEnumerable has a Reset() function. But in most cases it is not implemented. It is not even supposed to be implemented in most cases. Afaik it is only there for Backwards Compatabilty with some old COM stuff.
b) make a sub-interface just for the property
c) Verify the Interface is properly implemented via is checks (throw exceptions thows if nessesary, like Array.Sort will throw a InvalidOperation one), generic constraints, proper argument types and the like.
I have an interface:
interface ISqlite
{
void insert();
void update();
void delete();
void select();
}
And custom service class:
class SqliteService
{
public SQLiteDatabase driver;
public SqliteService() {
SqliteConnection(new SQLiteDatabase());
}
public void SqliteConnection(SQLiteDatabase driver)
{
this.driver = driver;
}
public void select(ISqlite select) {
select.select();
}
public void insert(ISqlite insert) {
insert.insert();
}
public void delete(ISqlite delete)
{
delete.delete();
}
}
And last class Pacients that realizes ISqlite interface:
class Pacients: ISqlite
{
public List<ClientJson> pacients;
public Pacients() {
this.pacients = new List<ClientJson>();
}
public void add(ClientJson data) {
this.pacients.Add(data);
}
public void insert()
{
throw new NotImplementedException();
}
/* Others methos from interface */
}
I try to use my code like as:
/* Create instance of service class */
SqliteService serviceSqlite = new SqliteService();
/* Create instance of class */
Pacients pacient = new Pacients();
pacient.add(client);
serviceSqlite.insert(pacient);
As you can see above I send object pacient that realizes interface ISqlite to service. It means that will be called method insert from object pacient.
Problem is that I dont understand how to add data in this method using external class: SQLiteDatabase()? How to get access to this.driver in service class from object pacient?
Edit 1
I think I must move instance of connection new SQLiteDatabase() to db inside Pacients class is not it?
Generally speaking, I would favor a solution where the data objects themselves don't know anything about how they're stored, i.e. they have no knowledge of the class that communicates with the database. Many ORMs do just that.
Of course it might not be easy depending on the specifics of your situation... Try to examine what your methods on each object actually need; generally speaking they need the values of properties, and what column each property corresponds to, right? So any external class can do this if it knows these bits of information. You can specify the name of the column with a custom attribute on each property (and if the attribute isn't there, the column must have the same name as the property).
And again, this is the most basic thing that ORMs (Object Relational Mappers) do, and in addition they also manage more complicated things like relationships between objects/tables. I'm sure there are many ORMs that work with SqlLite. If you're OK with taking the time to learn the specifics of an ORM, that's what I would recommend using - although they're not silver bullets and will never satisfy all possible requirements, they are in my opinion perfect for automating the most common day to day things.
More to the point of the question, you can of course make it work like that if you pass the SQLiteDatabase object to the methods, or keep it in a private field and require it in the constructor or otherwise make sure that it's available when you need it; there's no other simple solution I can think of. And like you pointed out, it implies a certain degree of coupling.
You can change the signature of interface's methods to pass an SQLiteDatabase object.
interface ISqlite
{
void insert(SQLiteDatabase driver);
void update(SQLiteDatabase driver);
void delete(SQLiteDatabase driver);
void select(SQLiteDatabase driver);
}
Example call from the service:
public void insert(ISqlite insert)
{
insert.insert(driver);
}
I think you can figure out the rest by yourself.
Feel free to load your guns and take aim, but I want to understand why you shouldn't do this.
I have created a custom class designed to replace any instances of List (which I use to update XML objects behind them):
public class ListwAddRemove<T> : List<T> {
public event EventHandler<ListModifyEventArgs> OnAdd;
public event EventHandler<ListModifyEventArgs> OnRemove;
new public void Add(T o) {
base.Add(o);
if (OnAdd != null) {
OnAdd(this, new ListModifyEventArgs(o));
}
}
new public void Remove(T o) {
base.Remove(o);
if (OnRemove != null) {
OnRemove(this, new ListModifyEventArgs(o));
}
}
}
The idea is whenever I add or remove an item from this list my bound events will fire and I can deal with the XML behind automatically.
This works like a charm, so far so good.
But how do I handle a conversion between object.ToList() and my derived version?
A lot of people are saying you should derive from Collection instead... why?
You should derive from Collection<T> because it's designed to allow you to override InsertItem, and RemoveItem to add custom behavior such as what you're doing (also SetItem, to add custom behavior when changing an existing item).
It can therefore be used as an IList<T>, and any insertion/removal will automatically use the customisation.
In your case, anyone who casts to IList<T> or the base class List<T> will bypass your custom Add/Remove functionality.
Collection<T> also provides a constructor to wrap an existing list. You can expose this from your derived class to wrap a list generated by Enumerable<T>.ToList().
UPDATE
Whats the syntax to expose the constructor please?
Very simple:
public class ListwAddRemove<T> : Collection<T>
{
public ListwAddRemove<T>()
{
}
public ListwAddRemove<T>(IList<T> list) : base(list)
{
}
... implementation of overrides for InsertItem, SetItem, RemoveItem ...
}
Then use it as follows:
IList<SomeType> list = ....ToList();
ListwAddRemove<SomeType> myList = new ListwAddRemove<SomeType>(list);
For one,
void DoSomeAddingToList(List<int> list) {
list.Add(1);
}
var list = new ListwAddRemove<int>();
DoSomeAddingToList(list);
will not trigger the events. That might lead to strange effect, especially if you're not the only one using the class.
List<T> defines a very specific behaviour for Add and Remove (since it's a concrete class), and users might rely on exactly this behaviour.
I think this is generally true for using a new modifier, so this language feature should be used with caution, especially on public methods.
As others have mentioned, implementing IList<T> (using delegation/aggregation) is probably the better choice.
So I've got these classes that expose a collection of child objects.
I don't want other classes adding or removing objects from collections because I need to wire into events in the child objects, so as they get added or removed I want to be able to do additional processing. But I really love the ease of manipulating generics internally.
Did I mention this is a WPF app so I need INotifySupport?
The best I can come up with is something like this.
public class foo : INotifyPropertyChanged
{
protected List<ChildFoo> _Children = new List<ChildFoo>();
public foo()
{
}
public void AddChild(ChildFoo newChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
public void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo[] Children
{
get
{
return _Children.ToArray();
}
}
}
Are there serious flaws with this design that I'm not seeing?
Every time the Children property is accessed we get the overhead of converting list to an array.
Any advice on this would be great.
This is what I do for normal code:
Public Readonly Property Childern As ObjectModel.ReadOnlyCollection(Of Child)
Get
Return New ObjectModel.ReadOnlyCollection(Of Child)(_ChildernList)
End Get
End Property
For WPF code I would just expose a subclass of ObservableCollection.
You should use ObservableCollection as field in your class, you then have full access to modify collection. Then expose this as ReadonlyObservableCollection via property.
And if you dont change collection itself (eg. nochildren = new ObservableCollection(), you should make field readonly), then you dont need any kind of notifyPropertyChanged on this property, because it doesnt change and collection itself handles those events for its children.
public class Child
{
public int Value { get; set; }
}
class MyClassWithReadonlyCollection
{
private readonly ObservableCollection<Child> _children = new ObservableCollection<Child>();
public MyClassWithReadonlyCollection()
{
_children.Add(new Child());
}
//No need to NotifyPropertyChange, because property doesnt change and collection handles this internaly
public ReadOnlyObservableCollection<Child> Children { get { return new ReadOnlyObservableCollection<Child>(_children); } }
}
I changed the "add child" and "remove child" to protected since you are saying you don't want other classes modifying your collection. I changed your List to ObservableCollection so you can recieve collection changed notifications. Since you are using an IList there is no need to call ToArray(), just access directly.
try this:
public class foo : INotifyPropertyChanged
{
protected ObservableCollection<ChildFoo> _Children = new ObservableCollection<ChildFoo>();
public foo() { }
protected void AddChild(ChildFoo oldChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
protected void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo this[int n]
{
get
{
return _Children[n];
}
}
}
You could subclass BindingList and set AllowNew/AllowRemove to false. In your Child Add/Remove methods, you can set it to true, make the changes, then set it back to false. (Of course, you need to hide set access to AllowNew/AllowRemove from outside callers as well).
Another option - subclass Observable collection and override the InsertItem, RemoveItem, etc methods to behave as AddChild/RemoveChild would behave. Then callers can still access it in familiar ways, but not bypass your custom logic.
Subclassing an existing collection class is probably going to be easier (for you and the consumer) than wrapping a collection in another class.
I have some classes inherit from existing Windows Controls like TextBox and DateTimePicker, ..etc
I want to add custom functionalities for these classes like (Read, Alert, ...etc)
these added functionalities are the same in all these classes
The problem is: these classes inherited from difference parents so I can't put my added functionalities in the parent class,
What's the best practice in this case:
repeat the code in each inherited
class
Use a separated class have the
functionalities as Static Methods
with parameter from an interface, implement this interface for the classes and
then pass them.
Use a separated class like the second approach but with Dynamic parameter (which added in C# 4.0)
or other !!
Thanks in advance
I'd consider option 4: composition.
First, define your set of functionality. We'll assume that your partial list is exclusive, so "Read" and "Alert."
Second, create a single class that implements this functionality, something like MyCommonControlBehaviors. I'd prefer this implementation not be static if possible, though, it may be generic.
public MyCommonControlBehaviors
{
public Whatever Read() { /* ... */ }
public void Alert() {}
}
Third, use composition to add an instance of this class to each of your custom control types and expose that functionality through your custom control:
public class MyCustomControl
{
private MyCommonControlBehaviors common; // Composition
public Whatever Read() { return this.common.Read(); }
public void Alert() { this.common.Alert(); }
}
Depending on specifics, you can get creative to the degree necessary. E.g., perhaps your custom behaviors need to interact with private control data. In that case, make your control implement a common ICommonBehaviorHost interface that your common behaviors need. Then pass the control into the behavior class on construction as an instance of ICommonBehaviorHost:
public interface ICommonBehaviorHost
{
void Notify();
}
public class MyCommonControlBehaviors
{
ICommonBehaviorHost hst = null;
public MyCommonControlBehaviors(ICommonBehaviorHost host)
{
this.hst = host;
}
public void Alert() { this.hst.Notify(); } // Calls back into the hosting control
// ...
}
public class MyCustomControl : ICommonBehaviorHost
{
private MyCommonControlBehaviors common = null;
public MyCustomControl() { common = new MyCommonControlBehaviors(this); }
public Whatever Read() { return this.common.Read(); }
public void Alert() { this.common.Alert(); }
void ICommonBehaviorHost.Notify() { /* called by this.common */ }
}
Use Composition instead of Inheritence!
If you must, what I would probably do is create extension methods for each class and then reference the actual coded needed for these in some other object all the extension methods can call.
This way the code isn't duplicated, and the extension methods make it look like the methods should be in the object.
It's the same essentially by creating a static method and doing: Functions.DoSomething(my_Object);
But I always like: my_Object.DoSomething() better in an OO language.
I would suggest defining an interface for the behaviors, and then (to keep from repeating yourself) create extension methods on that interface definition for your shared methods. (Kinda like your second option, only with extension methods instead of totally static methods).