In general terms, a program I'm making involves storing a small number of entries (probably less than 30 at any given time) which can be categorized. I want to allow these entries to be seen but not altered from outside the class using them. I made a class called Entry which could be modified and another called ReadOnlyEntry which is a wrapper for an Entry object. The easiest way to organize these Entry objects it seems is to create a List<List<Entry>>, where each List<Entry> is a category. But then exposing that data in a readonly way became messy and complicated. I realized I would have to have one object of each of the following types:
List<List<Entry>> data;
List<List<ReadOnlyEntry>> // Where each ReadOnlyEntry is a wrapper for the Entry in the same list and at the same index as its Entry object.
List<IReadOnlyCollection<ReadOnlyEntry>> // Where each IReadOnlyCollection is a wrapper for the List<ReadOnlyEntry> at the same index in data.
IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> readOnlyList // Which is a wrapper for the first item I listed.
The last item in the list would be exposed as public. The first lets me change entries, the second lets me add or delete entries, and the third lets me add or delete categories. I would have to keep these wrappers accurate whenever the data changes. This seems convoluted to me, so I'm wondering if there's a blatantly better way to handle this.
Edit 1:
To clarify, I know how to use List.asReadOnly(), and the stuff I proposed doing above will solve my problem. I'm just interested in hearing a better solution. Let me give you some code.
class Database
{
// Everything I described above takes place here.
// The data will be readable by this property:
public IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> Data
{
get
{
return readOnlyList;
}
}
// These methods will be used to modify the data.
public void AddEntry(stuff);
public void DeleteEntry(index);
public void MoveEntry(to another category);
public void AddCategory(stuff);
public void DeleteCategory(index);
}
You can use List<T>.AsReadOnly() to return ReadOnlyCollection<T>.
Also, you're torturing the List<T> class storing the data the way you are. Build your own hierarchy of classes which store your individual lists.
.NET collections should support covariance, but they don't support it themselves (instead some interfaces support covariance https://msdn.microsoft.com/ru-ru/library/dd233059.aspx). Covariance means List<Conctrete> behaves like subclass of List<Base> if Concrete is subclass of Base. You can use interfaces covariation or just use casting like this:
using System.Collections.Generic;
namespace MyApp
{
interface IEntry
{
}
class Entry : IEntry
{
}
class Program
{
private List<List<Entry>> _matrix = null;
public List<List<IEntry>> MatrixWithROElements
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public IReadOnlyList<List<IEntry>> MatrixWithRONumberOfRows
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public List<IReadOnlyList<IEntry>> MatrixWithRONumberOfColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry) as IReadOnlyList<IEntry>);
}
}
public IReadOnlyList<IReadOnlyList<IEntry>> MatrixWithRONumberOfRowsAndColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public void Main(string[] args)
{
}
}
}
Thanks to Matthew Watson for pointing on errors in my previous answer version.
You could make an interface for Entry which contains only getters; you would expose elements via this interface to provide read-only access:
public interface IEntry
{
int Value { get; }
}
The writable implementation would be simply:
public sealed class Entry : IEntry
{
public int Value { get; set; }
}
Now you can take advantage of the fact that you can return a List<List<Entry>> as a IReadOnlyCollection<IReadOnlyCollection<IEntry>> without having to do any extra work:
public sealed class Database
{
private readonly List<List<Entry>> _list = new List<List<Entry>>();
public Database()
{
// Create your list of lists.
List<Entry> innerList = new List<Entry>
{
new Entry {Value = 1},
new Entry {Value = 2}
};
_list.Add(innerList);
}
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data => _list;
}
Note how simple the implementation of the Data property is.
If you need to add new properties to IEntry you would also have to add them to Entry, but you wouldn't need to change the Database class.
If you're using C#5 or earlier, Data would look like this:
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
get { return _list; }
}
I have following structure:
public class Base : BaseViewModel
{
public string Name{ get; set; }
}
public class SubBase<T> : Base
{
public virtual IEnumerable<T> Values{ get; set; }
private T selectedValue;
public T SelectedValue
{
get { return selectedValue; }
set
{
selectedValue= value;
OnPropertyChanged();
}
}
}
The problem is that I create lists of BaseFiltr as follows
ObservableCollection<BaseFiltr>
and then I have one of elements from list which is of type BaseFiltr and I want to get its SelectedValue property but unfortunately it is not possible since it is placed in derived class. I cannot place this property in BaseFiltr since I would have to mark it as generic. BaseFiltr is created only for list's purpose to avoid setting as follows:
ObservableCollection<BaseFiltr<some type>>
Any suggestions what might be done? Thank you in advance.
I have one of elements from list which is of type BaseFiltr and I want to get its WybranaWartosc property
You have a fundamental problem - BaseFiltr does not have a WybranaWartosc property - only SubBaseFiltr<T> does. You could check each item to see if it's a SubBaseFiltr<T> and then cast and probe it's WybranaWartosc property.
BaseFiltr is created only for list's purpose to avoid setting as follows: ObservableCollection<BaseFiltr<some type>>
It appears you're sacrificing proper typing for a slight decrease in complexity. If your collection is really a collection of SubBaseFiltr<T> objects, then use that type.
I needed a structure that contains a pair of values, of which ones value would be changed. So my first thought was to use a KeyValueItem or a Tupple<,> but then I saw that they have only a getter. I can't realize why? What would you use in my case? I could create my own class, but is there any other way?
They are immutable types. The idea of immutable types is that they represent a value, and so cannot change. If you need a new value, you create a new one.
Let's say the first value of your tuple needs to change, just do this:
myValue = Tuple.Create(newValue, myValue.Item2);
To understand why immutability is important, consider a simple situation. I have a class that say contains a min and max temperatures. I could store that as two values and provide two properties to access them. Or I could store them as a tuple and provide a single property that supplies that tuple. If the tuple were mutable, other code could then change these min and max values, which would mean the min and max inside my class will have changed. By making the tuple immutable, I can safely pass out both values at once, secure in the knowledge that other code can't tamper with them.
You can create your own implementation:
public class Pair<T, U> {
public Pair() {
}
public Pair(T first, U second) {
this.First = first;
this.Second = second;
}
public T First { get; set; }
public U Second { get; set; }
};
Tuples are read only in C#. This is explained in the answer here, mainly due to their nature from functional programming.
You should create your own MutableTuple implementation that allows modification.
Things to consider:
You might want to override Equals and GetHashCode
You might want it to be sortable on the First element of the tuple (IComparable).
Tuples historically come from functional programming, where everything is supposed to be immutable. You can learn more about functional programming here:
Functional Programming
What are the benefits of functional programming?
And to have benefits of the historical approach, Tuples in C# have been designed the same way. If you really want mutable tuples, you can easily implement that yourself:
public class MutableTuple<TFirst, TSecond>
{
public TFirst { get; set; }
public TSecond { get; set; }
}
I haven't used LINQ extensively but the more I use it the more I realize how powerful it can be. Using the LinqDataSource.OrderBy clause is obviously easy if you want to sort from a property on the bounded items but what if you want to sort the items based on a method return? Take this class for instance (please ignore the quirky design - it's just used to emphasize my point):
public class DataItem
{
private string Id { get; set; }
private int SortValue { get; set; }
public DataItem(string id, int sortValue)
{
this.Id = id;
this.SortValue = sortValue;
}
public int GetSortValue()
{
return SortValue;
}
}
Is there a way that I can set the orderby expression on the LinqDataSource so that it uses the value returned from GetSortValue (i.e order by other members than properties) but without altering the DataItem class?
If the method has no parameters you could wrap it with a property?
public int SortOrderBy { get { return GetSortValue(); } }
Edit: This will also work if the parameters are constants or class fields/properties.
The MSDN docs mention that it is indeed possible to do custom sorting but I might have misinterpreted your question.
In C# I find indexed properties extremely useful. For example:
var myObj = new MyClass();
myObj[42] = "hello";
Console.WriteLine(myObj[42]);
However as far as I know there is no syntactic sugar to support fields that themselves support indexing (please correct me if I am wrong). For example:
var myObj = new MyClass();
myObj.field[42] = "hello";
Console.WriteLine(myObj.field[42]);
The reason I need this is that I am already using the index property on my class, but I have GetNumX(), GetX(), and SetX() functions as follows:
public int NumTargetSlots {
get { return _Maker.NumRefs; }
}
public ReferenceTarget GetTarget(int n) {
return ReferenceTarget.Create(_Maker.GetReference(n));
}
public void SetTarget(int n, ReferenceTarget rt) {
_Maker.ReplaceReference(n, rt._Target, true);
}
As you can probably see exposing these as one indexable field property would make more sense. I could write a custom class to achieve this every time I want the syntactic sugar but all of the boilerplate code just seem unnecessary.
So I wrote a custom class to encapsulate the boilerplate and to make it easy to create properties that can be indexed . This way I can add a new property as follows:
public IndexedProperty<ReferenceTarget> TargetArray {
get {
return new IndexedProperty<int, ReferenceTarget>(
(int n) => GetTarget(n),
(int n, ReferenceTarget rt) => SetTarget(n, rt));
}
}
The code for this new IndexedProperty class looks like:
public class IndexedProperty<IndexT, ValueT>
{
Action<IndexT, ValueT> setAction;
Func<IndexT, ValueT> getFunc;
public IndexedProperty(Func<IndexT, ValueT> getFunc, Action<IndexT, ValueT> setAction)
{
this.getFunc = getFunc;
this.setAction = setAction;
}
public ValueT this[IndexT i]
{
get {
return getFunc(i);
}
set {
setAction(i, value);
}
}
}
So my question is: is there a better way to do all of this?
Well to be specific, is there a more idiomatic way in C# to create an indexable field property, and if not how could I improve my IndexedProperty class?
EDIT: After further research, Jon Skeet calls this a "named indexer".
EDIT FOR 2022: This continues to get votes, but it probably isn't something I would use today primarily because it does push garbage collection in a way that would not be ideal at scale, if the property was being hit a lot. I remember this being a complicated topic, and I do not want to go deep on researching it right now, but I wonder if indexers could solve this problem today. See: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/
I found your idea useful, so I extended it. This may not technically be a proper answer since I'm not sure it squarely answers your question, but I thought it might be useful to people who came here looking for property indexers.
First, I needed to be able to support get-only and set-only properties, so I made a slight variation of your code for these scenarios:
Get and Set (very minor changes):
public class IndexedProperty<TIndex, TValue>
{
readonly Action<TIndex, TValue> SetAction;
readonly Func<TIndex, TValue> GetFunc;
public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction)
{
this.GetFunc = getFunc;
this.SetAction = setAction;
}
public TValue this[TIndex i]
{
get
{
return GetFunc(i);
}
set
{
SetAction(i, value);
}
}
}
Get Only:
public class ReadOnlyIndexedProperty<TIndex, TValue>
{
readonly Func<TIndex, TValue> GetFunc;
public ReadOnlyIndexedProperty(Func<TIndex, TValue> getFunc)
{
this.GetFunc = getFunc;
}
public TValue this[TIndex i]
{
get
{
return GetFunc(i);
}
}
}
Set Only:
public class WriteOnlyIndexedProperty<TIndex, TValue>
{
readonly Action<TIndex, TValue> SetAction;
public WriteOnlyIndexedProperty(Action<TIndex, TValue> setAction)
{
this.SetAction = setAction;
}
public TValue this[TIndex i]
{
set
{
SetAction(i, value);
}
}
}
Example
Here's a simple usage example. I inherit from Collection and create a named indexer, as Jon Skeet called it. This example is intended to be simple, not practical:
public class ExampleCollection<T> : Collection<T>
{
public IndexedProperty<int, T> ExampleProperty
{
get
{
return new IndexedProperty<int, T>(GetIndex, SetIndex);
}
}
private T GetIndex(int index)
{
return this[index];
}
private void SetIndex(int index, T value)
{
this[index] = value;
}
}
ExampleCollection in the Wild
This hastily constructed unit test shows how it looks when you ExampleCollection in a project:
[TestClass]
public class IndexPropertyTests
{
[TestMethod]
public void IndexPropertyTest()
{
var MyExample = new ExampleCollection<string>();
MyExample.Add("a");
MyExample.Add("b");
Assert.IsTrue(MyExample.ExampleProperty[0] == "a");
Assert.IsTrue(MyExample.ExampleProperty[1] == "b");
MyExample.ExampleProperty[0] = "c";
Assert.IsTrue(MyExample.ExampleProperty[0] == "c");
}
}
Finally, if you want to use the get-only and set-only versions, that looks like this:
public ReadOnlyIndexedProperty<int, T> ExampleProperty
{
get
{
return new ReadOnlyIndexedProperty<int, T>(GetIndex);
}
}
Or:
public WriteOnlyIndexedProperty<int, T> ExampleProperty
{
get
{
return new WriteOnlyIndexedProperty<int, T>(SetIndex);
}
}
In both cases, the result works the way you would expect a get-only/set-only property to behave.
Well, the simpliest is to have the property return an object which implements IList.
Remember that just because it implements IList doesn't mean it's a collection itself, just that it implements certain methods.
I think the design you've posted is the way to go, with the one difference that I would define an interface:
public interface IIndexed<IndexT, ValueT>
{
ValueT this[IndexT i] { get; set; }
}
And for common cases, I would use the class you put in the original question (which would implement this interface).
It would be nice if the base class library provided a suitable interface for us, but it doesn't. Returning an IList here would be a perversion.
This doesn't answer your question, but it's interesting to note that CIL supports making properties like you've described - some languages (For example, F#) will allow you to define them in such a way too.
The this[] indexer in C# is just a specific instance of one of these which is renamed to Item when you build your app. The C# compiler only knows how to read this one, so if you write a "named indexer" called Target in an F# library, and try to use it in a C#, the only way you could access the property is via the ... get_Target(int) and void set_Target(int, ...) methods. Sucks.
Why not have your class inherit IList then you can just use the index and add your own properties to it. Although you will still have the Add and Remove functions its not dishonest not to use them. Plus you may find it useful to have them furthur down the road.
For more information about Lists and Arrays check out:
Which is better to use array or List<>?
EDIT:
MSDN has an article on index properties you may want to take a look at. Doesn't seem to complicated just tedious.
http://msdn.microsoft.com/en-us/library/aa288464(VS.71).aspx
There is another option where you can create an alternative Add method but depending on the type of object your add method may not always be called. Explained here:
How do I override List<T>'s Add method in C#?
EDIT 2: Similar to the first post
Why don't you have a hidden list object in your class and then just create your own methods for obtaining the data. That way Add and Remove aren't seen and the list is already indexed.
Also what do you mean by "named indexer" are you looking for the equivalent of the row["My_Column_Name"]. Theres an MSDN article I found that may be useful as it seems to show the basic way to implement that property.
http://msdn.microsoft.com/en-us/library/146h6tk5.aspx
class Test
{
private List<T> index;
public T this[string name]{ get; set; }
public T this[int i]
{
get
{
return index[i];
}
set
{
index[i] = value;
}
}
}
After some research, I came up with a slightly different solution that better fitted my needs. The example is a little concocted, but it does suit what I need it to adapt it to.
Usage:
MyClass MC = new MyClass();
int x = MC.IntProperty[5];
And the code to make it work:
public class MyClass
{
public readonly IntIndexing IntProperty;
public MyClass()
{
IntProperty = new IntIndexing(this);
}
private int GetInt(int index)
{
switch (index)
{
case 1:
return 56;
case 2:
return 47;
case 3:
return 88;
case 4:
return 12;
case 5:
return 32;
default:
return -1;
}
}
public class IntIndexing
{
private MyClass MC;
internal IntIndexing(MyClass mc)
{
MC = mc;
}
public int this[int index]
{
get { return MC.GetInt(index); }
}
}
}