How I do it currently:
class Foo
{
public int[] A { get { return (int[])a.Clone(); } }
private int[] a;
}
I think it's bad because it creates a clone and casts whenever I access it. I know I can work around it by introducing an additional variable like this
var foo = new Foo();
// as soon as you have to access foo.A do this
int[] fooA = foo.A;
// use fooA instead of foo.A from now on
but still it just looks bad.
I also dislike the java way of encapsulating
int get(int index) { return a[index]; }
because I dont get the advantages of using an array.
Is there any better way to do this?
edit: I want an array of encapsulated variables. The problem is that
public int[] A { get; private set; }
is not an array of encapsulated variables because I can modify elements of the array from outside of the class.
edit: It should also work with multidimensional arrays
Arrays implement IReadOnlyList<T> which exposes all of the relevant information you want (an iterator, an indexer, count, etc.) without exposing any of the mutable functionality of the array.
class Foo
{
public IReadOnlyList<int> A { get { return a; } }
private int[] a;
}
alternatively, you could use an iterator/generator to return the items as requested:
class Foo
{
public IEnumerable<int> A
{
get
{
foreach (int i in a)
yield return i;
}
}
private int[] a;
}
... then iterate over them normally or use LINQ to get them as a new array or other type of collection:
int[] arr = foo.A.ToArray();
Why not expose A as a implementation of IReadOnlyList
class Foo
{
public IReadOnlyList<int> A { get { return a; } }
private int[] a;
}
This allows you to return the Array as a collection where they can use the index but cannot change the contents of the array itself.
sounds like you need an indexer
...
public int this[int i]{
get{return a[i];}
set{a[i] = value;}
}
....
https://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
Related
public class MyStuff : ICloneable
{
public int A {get;set;}
public int B {get;set;}
public object Clone()
{
MyStuff Copy = (MyStuff)MemberwiseClone();
return Copy;
}
}
Now lets assume i have an array of MyStuff
MyStuff[] MyStuffObjs = PopulateMyStuff();
What is the quickest/easiest way to create a clone of MyStuffObjs implementing the Clone method?
I know i can iterate through the collection and copy each one.
List<MyStuff> NewStuff = new List<MyStuff>();
foreach(var Stuff in MyStuffObjs)
{
NewStuff.Add(Stuff.Clone());
}
return NewStuff.ToArray();
Surely there is a better way?
You can use Linq for that:
return MyStuffObjs.Select(item => (MyStuff)item.Clone()).ToArray();
You can even create a helper method like this
public static class MyExtensions
{
public static T[] DeepClone<T>(this T[] source) where T : ICloneable
{
return source.Select(item => (T)item.Clone()).ToArray();
}
}
and use it as follows
return MyStuffObjs.DeepClone();
Just Select/ToArray would be shorter, but really there is nothing significantly better than iterating over all items and calling Clone.
Shorter code:
return MyStuffObjs.Select( x=> x.Clone()).ToArray();
A bit faster code - pre-allocate array instead of using list:
MyStuff[] cloned = new MyStuff[MyStuffObjs.Length];
for (var i = 0; i < cloned.Lenght; i++)
{
cloned[i] = MyStuffObjs[i].Clone();
}
I have a a class that has an integer array property and I am trying to figure out the right syntax for it. The integer array gets instantiated in the class constructor.
class DemoClass
{
private int[] myNumbers;
public int[] MyNumbers
{
get { /* Some logic */ }
set { /* Some logic */ }
}
public DemoClass(int elements)
{
// Here, the array should get instantiated using the elements.
}
}
How does the get/set block syntax work if I want my client code to retrieve a number from the array through the property MyNumbers?
How can I send it the right index?
What do I have to initialize?
Are you looking for:
class DemoClass
{
public int[] MyNumbers { get; private set; }
public DemoClass(int elements)
{
MyNumbers = new int[elements];
}
}
As for normal properties that do nothing except publicize a private field (as you seem to want):
private int[] myNumbers;
public int[] MyNumbers
{
get { return myNumbers; }
set { myNumbers = value; }
}
CA1819: Properties should not return arrays
http://msdn.microsoft.com/en-us/library/0fss9skc.aspx
Arrays returned by properties are not write-protected, even if the property is read-only. To keep the array tamper-proof, the property must return a copy of the array. Typically, users will not understand the adverse performance implications of calling such a property. Specifically, they might use the property as an indexed property.
To fix a violation of this rule, either make the property a method or change the property to return a collection instead of an array
If the number of element in the array is fixed, I would only provide a getter for the array and leave off the setter. You will still be able to assign values to individual elements in the array, but this will prevent someone from swapping the whole array out from under you (or setting it to null. The code would look like this:
class DemoClass
{
public int[] MyNumbers
{ get; private set; }
public DemoClass(int elements)
{
MyNumbers = new int[elements];
}
}
If the number of elements are not fixed, then you should use a List<int> rather than an array, and then you definitely want a property with no setter.
class DemoClass
{
private int[] myNumbers;
public int[] MyNumbers
{
get { return myNumbers; }
set { myNumbers = value; }
}
public DemoClass(int[] elements)
{
myNumbers = elements;
// Here, the array should get instantiated using the elements.
}
}
It is called Auto-Implemented Properties . So if you have syntax like
public int[] MyNumbers { get; set; }
C# compiler will automatically create for you backing field. This feature was introduced in C# 3.0, and before that you always had to implement property with backing field.
You can read more at: New C# "Orcas" Language Features: Automatic Properties, Object Initializers, and Collection Initializers
class DemoClass
{
private int[] myNumbers;
public int[] MyNumbers
{
get { return myNumbers; }
set { myNumbers = value;}
}
public DemoClass(int elements)
{
// Here, the array should get instantiated using the elements.
MyNumbers = new int[5] { 1, 2, 3, 4, 5};
}
}
Alright, so I'm currently learning inheritance, and I've done something, this is the code:
class array
{
int [] arr;
public array(int[] arr)
{
this.arr = arr;
}
public int Biggest()
{
return arr.Max();
}
public int Min()
{
return arr.Min();
}
public int SumArr()
{
return arr.Sum();
}
}
class array2 : array
{
public array2(int [] arr):base(arr)
{
}
public double Average()
{
return
}
}
Now, in the derived class I need to get the average of the array and I can't do arr.Average()
The error says: Error 1 'ConsoleApplication1.array.arr' is inaccessible due to its protection level C:\Users\x\AppData\Local\Temporary Projects\ConsoleApplication1\Program.cs 35 20 ConsoleApplication1
Anyone can tell me what am I doing wrong?
Thanks for helpers!
arr is declared as private since you didn't specify a visibility type. If you change it to protected, then your subclass array2 will be able to access it.
protected int [] arr;
In your example, you've made the arr array implictly private where you have omitted the modifier itself. If you want to provide access to said field in your derived classes, you'd need to use an access modifier of protected:
protected int[] arr;
But it's not recommend to expose fields this way, as fields should really be for private class state. What you should do, is encapsulate read-only access to that field, via a property:
protected int[] Array {
get { return this.arr; }
}
Which means in your derived class, you can:
public double Average()
{
return this.Array.Average();
}
In C#, the default access level for a class member is private. You haven't specified an access level for int [] arr, so it is private and hence visible to the other class.
That's because your arr field is private. consider using a write-private read-protected property instead, like this:
class array
{
protected int[] arr {get; private set; }
public array(int[] arr)
{
this.arr = arr;
}
public int Biggest()
{
return arr.Max();
}
public int Min()
{
return arr.Min();
}
public int SumArr()
{
return arr.Sum();
}
}
class array2 : array
{
public array2(int [] arr):base(arr)
{
}
public double Average()
{
return arr.Average();
}
}
Since you didn't explicitly define an access type for arr, it is implicitly set to private. To be able to access this from the derived class, you should set it to protected.
protected int [] arr;
There are better ways to do this, e.g. through a property, but that's the general idea.
Add public or protected to the arr variable:
public int [] arr;
protected int [] arr;
If you don't specify otherwise, the compiler will default to making your declarations private.
Seems like I can't do this:
private int[,] _table = new int[9, 9];
private ReadOnlyCollection<int[,]> _tableReadOnly = new ReadOnlyCollection<int[,]>(_table);
My idea is to have a property that let's the user read _table, but I don't want to let them change it, so I thought I could use ReadOnlyCollection for the matter.
The ReadOnlyCollection is a one dimensional collection. You could make a ReadOnlyCollection<ReadOnlyCollection<int>>, or make your own two dimensional wrapper class, something like:
public class ReadOnlyMatrix<T> {
private T[,] _data;
public ReadOnlyMatrix(T[,] data) {
_data = data;
}
public T this[int x, int y] {
get {
return _data[x, y];
}
}
}
The problem is you're trying to wrap a 2D mutable structure with a 1D read only structure. You'll need several levels of nesting to accomplish this.
ReadOnlyCollection<ReadOnlyCollection<int>>
The downside to this approach though is that it will essentially force you to have the entire table in memory twice. ReadOnlyCollection<T> requires a List<T> as the sole constructor argument. So you will end up copying each one of your rows into a new List<int>.
Another way to accomplish this though is to use a property indexer to return the value directly without allowing for mutation.
public int this[int i, int j] {
get { return _table[i,j]; }
}
This allows consumers to read the data without every having to mutate it.
You could do something like:
public class ReadOnly2DArray<T>
{
T[,] _array;
public ReadOnly2DArray(T[,] arrayToWrap)
{
_array = arrayToWrap;
}
public T this[int x, int y]
{
get { return _array[x, y]; }
}
}
possibly adding other methods of the Array class (Length property, GetLength method, ...) if you need them.
You'd then use it something like:
int[,] a = new int[2, 2];
ReadOnly2DArray<int> wrapper = new ReadOnly2DArray<int>(a);
int value = wrapper[0, 0]; // Can read values
//wrapper[0, 0] = value; // Won't compile
I'm not entirely sure I understand the direction you were taking, but based on your description of what you're trying to accomplish, it seems to me that you can just do the following:
private int[,] _table = new int[9, 9];
public int[,] Table
{
get
{
return _table;
}
}
I have an interface with:
IList<int> CategoryIDs {get;set;}
Then a class that inherits this interface:
public IList<int> CategoryIDs
{
get {} // this part works
set { _categoryIDs = value; // error!
}
The set part of the accessor reports an error:
cannot implicity convert type IList<int> to List<int>.
What should I do? confused.
IList is an interface, List is a concrete class. List may implement IList, but other classes may as well, so you cannot assign an IList to a List without a cast. Try something like this instead:
private IList<int> _list = new List();
public IList<int> List
{
get { return _list; }
set { _list = value; }
}
Of course, you should not be writing code in your class that assumes that List or _list is actually a list, you should be treating it generically as an IList.
Two things:
1) It's usually a bad idea to put a setter on an IList<T> member. You typically want people to work on your existing list, but not replace it completely. This would look like:
public interface IMyInterface {
IList<int> CategoryIDs {get;} // Only put get
}
public class MyClass : IMyInterface
{
List<int> categoryIDs;
public IList<int> CategoryIDs
{
get { return this.categoryIDs; }
}
}
2) If you do need to do that, you'll have to either cast the IList<T> to a List<T> in order to set it, or make a copy.
public interface IMyInterface {
IList<int> CategoryIDs {get;set;}
}
public class MyClass : IMyInterface
{
List<int> categoryIDs;
public IList<int> CategoryIDs
{
get { return this.categoryIDs; }
set
{
List<int> asList = value as List<int>;
if (asList != null)
this.categoryIDs = asList;
else
this.categoryIDs = new List<int>(value); // Copy values across into new list!
}
}
}
Either way, this approach is a bit "clunky" feeling.
You can instantiate and assign a List just fine with a minor tweak:
private IList<int> _categoryIDs; // use IList instead of List
public IList<int> CategoryIDs
{
get { return _categoryIDs; }
set { _categoryIDs = value; }
}
Apparently, your field _categoryIDs is declared as List<T>, while your property is IList<T> (or even IList, it's hard to say with broken source code formatting in the question). IList<T> (and IList) is an interface; List<T> is a class implementing that interface. Because of that, you can assign List reference to variable of type IList, but not vice versa.
Your set function is missing the second bracket.