Advantages of indexers over object array? - c#

I read about indexers in MSDN - Indexers which explains how we can use objects like array with index i.e. just like normal Array. However, I think we can create array of objects like
point[] array = new point[100];
So what is the special advantages Indexer over object array?

If all you are after is a collection of objects then an indexer has absolutely no benefit over an array. However, if you need to store state as well as a collection, that's where an indexer shines.
For example, consider the following
public class Tree
{
private Branch[] branches = new Branch[100];
...
public string Name { get; set; }
public Branch this[int i]
{
get
{
return branches[i];
}
}
}
Tree holds an internal collection but also has state of it's own. Having an indexer property allows for simple access to the underlying collection e.g.
tree.Name = "Tree";
var branch = tree[0];

Not in this case that you have mentioned above. However, if you have anything that cannot be represented as an array will be a good example for Indexers to be used.
One .Net framework example is Dictionary. If you see the definition of Dictionary type in .Net you will find that they let you get an access of value through key. So that is a good example of using indexers where the index is presented as string.
Without indexers, how would you do that? of course by index value but it cannot be of type string then, will that be user friendly? I guess not!
So indexers gives you an opportunity to represent your code well.
Similarly, in case of point type, of course you can access the value of by index i.e. 0,1,2...99. What if you want to make more user friendly, such as point["x"]. That is where Indexers will help you.
Another example I could think of how about if you want to access your stack like s1 instead of push and s[0] instead of pop method.
There is a very good example of indexers by Microsoft where you can access file byte by byte by providing character location as index.
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx

In your line of code, you've defined an array of point objects, whatever those might be.
point[] array = new point[100];
Assuming you have direct access to the array, you can access the first element in your array like this:
var firstPoint = array[0];
The page you linked to is showing you how you could access that array, if it were defined inside your class, and you didn't have direct access to the array (since it's private).
For example, we could modify the example on that page to use your array:
class SampleCollection
{
private Point[] arr = new Point[100];
public Point this[int i]
{
get { return arr[i]; }
set { arr[i] = value; }
}
}
Then you could access the first element in the array like this:
var sc = new SampleCollection();
var item1 = sc[0];

That isn't an indexer.
An indexer is not used to create an array of objects, it is actually an operator overload to the '[]' operator.
An example for it's use would be if you wanted to make a List wrapper class.
In order to preserve the square braces functionality you would need (and want) to override the square braces operator. This is done via an indexer method.

Related

Passing a value by reference to List.Add()

How could I pass a value by reference to the List?
int x = 2;
List<int> newList = new List<int>();
newList.Add(x);
System.Console.WriteLine(x);
x = 7;
System.Console.WriteLine(newList[0]);
newList[0] = 10;
System.Console.WriteLine(x);
My objective is elements on the list to be related with the previous ones. In C++ I would use a list of pointers, however right now I feel hopeless.
You can't do it with value types.You need to use a reference type.
(change) You can't do it with object too, you need to define your custom class which has a int property. If you use object it will be automatically perform boxing and unboxing.And actual value never affected.
I mean something like this:
MyInteger x = new MyInteger(2);
List<MyInteger> newList = new List<MyInteger>();
newList.Add(x);
Console.WriteLine(x.Value);
x.Value = 7;
Console.WriteLine(newList[0].Value);
newList[0].Value = 10;
Console.WriteLine(x.Value);
class MyInteger
{
public MyInteger(int value)
{
Value = value;
}
public int Value { get; set; }
}
ints are primitives, so you are not passing around a pointer,but the value it self.
Pointers are implicit in C#,so you can wrap ints in an object and pass that object around instead and you will be passing a pointer to the object.
You can't store value types in a .NET generic collection and access them by reference. What you could do is what Simon Whitehead suggested.
I see few solutions of this problem:
1) Create a class which will hold the integer (and possibly other values you might need)
2) Write "unsafe" code. .NET allows usage of pointers if you enable this for your project. This might even require creating custom collection classes.
3) Restructure your algorithm to not require references. E.g. save indexes of values you wish to change.

C# Public variables in a class

I have a class which has a 2D jagged array declared in it's constructor, and in that class I have two methods called GetXY and SetXY, that modify said array.
However, I am unsure whether I should use these methods or in fact declare the grid as public, meaning there would be 2 ways of setting and reading values in the array, like this:
ProceduralGrid pg = new ProceduralGrid(10, 10);
pg.grid[0][0] = 2;
pg.SetXY(0, 0, 2);
Which one shall I use, and why?
Why not use
public T this[int x, int y]
{
get
{
return grid[x][y];
}
set
{
grid[x][y] = value;
}
}
Naturally check for valid x and y etc...
Use methods to access the array. Either SetXY or an indexer as suggested be Alessandro. That way, you can later change the implementation without changing your class interface.
It is best to use methods to set variables that are used inernally.
This way you can protect your inner object and are free to implement extra validation or modify the object as required.
This allows you to easily change the behaviour of that object later on.

Length of string array via reflection

Is it possible to know the length of a string array - without having an object instance - via reflection?
E.g. in this case: 2.
public string[] Key
{
get { return new string[] { Name, Type }; }
}
EDIT: ok, I will not try to do this, it doesn't make much sense.
Perhaps you mean "without having the exact type of the Array". C# Arrays all derive from Array, so you can cast an Array reference to Array and use the Length property.
If you TRULY wants to reflect the property,
var type = typeof(MyClass);
var prop = type.GetProperty("Key");
var method = prop.GetGetMethod();
var body = method.GetMethodBody();
var ils = body.GetILAsByteArray();
from here you'll have to use one of the various libraries to decode bytes to IL OpCodes (for example https://gist.github.com/104001) . The OpCode you are looking for is newarr. The last push of an int32 before the newarr is the size of the array.
You have two things going on there... telling the length of an array is pretty simple once you have an array; you just call .Length (in the case of a vector).
However, you mention an instance, and you are showing an instance property; which makes me think it is the containing object you lack. In which case... no. You can't make a virtcall on a null instance. And trying to use static-call on an instance member of a class is very evil; IIRC the runtime will kick you for this.
You could, however, make it a static property just by adding the static modifier. Then you just pass in null as the instance to reflection.
I guess you mean you want to know the size of the array the property will return if it were called?
I don't think you can do it sensibly.
If the property had a conditional then it could return different sized arrays, so
you'd have to evaluate the property to know the size. Which could have side effects or be dependent on other values in the object (or statics).
Consider this one:-
static public int n;
public string[] Key
{
get {
if (n > 1)
return new string[] { "Name", "Type" };
else
return new string[] { "Name", "Type", "Cheese" };
}
}
Basically, you'd have to run the code.

Why Can I Change Struct's int[] Property from Method Without Specifying "ref"?

From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.

Store a reference to a string

I have a class that has 3 string properties. I want to store these in a list so that when I make changes to the strings of the list they also get updated in the class.
This would be easy to do if I was using class object, but string seems to behave differently. It seems to make a copy of the object for the list rather then have a pointer to the object. How am I supposed to do this is C#? If this is not possible is there a better way?
The problem with strings is that they are immutable. In other words, you can never change a string once it is created.
Thus, if you want to 'change' a string, you must remove the original from the List, and store the result back into the list. Example:
string a = "abcdefg";
List<String> list = new List<String>();
list.add(a);
a = a.Substring(0, 5);
That code does nothing because the string a is pointing to never changes. It just points to a new string.
In .NET, strings are immutable. If you change the string, you are in fact creating a new one and modifying the reference.
I would consider using a StringBuilder object to address your problem.
Strings are immutable. You can change a reference to point to another string but you cannot modify a string such that other references to it change value as well (except by unsafe, completely dangerous reflective code)
What you want to do is deal with this either through using a mutable alternative, (such as a StringBuilder) or via explicit indirection. I'll show you the latter:
public class Props
{
private readonly string[] data = new string[2];
public string Foo {
get { return data[0]; }
}
public string Bar {
get { return data[1]; }
}
public IList<string> ModifyValueButNoInsertsList { get { return data;} }
}
Really you should consider actually using string[] rather than IList in this situation as it makes it clear inserts are forbidden, only alterations of the values. Since string[] implements IList<string> this is unlikely to be a problem
Since strings are immutable, the simplest work-around is to instead store the reference to a string array with one element. Replacing that element will then be noticed by anyone with a reference to the array.
Strings in C# are immutable, so you cannot change a string in C# - you can only create new strings.
You could rather store a class that has a string member
class StringHolder {
public StringHolder(string s) { str = s;}
public string str;
}
...
List<StringHolder> l1 = new List<StringHolder>();
List<StringHolder> l2 = new List<StringHolder>();
List<StringHolder> l3 = new List<StringHolder>();
StringHolder h = new StringHolder("Test\n");
l1.add(h);
l2.add(h);
l3.add(h);
h.str = h.str.Replace("\n","");
Now all lists refer to the same StringHolder and will naturally see the same string.
Another option is to store StringBuilder objects in your lists instead of a String.
class StringHolder
{
public string Value { get; set; }
}
Keep a list of those instead of just strings. Then you can get/set the Value property to update the string value.
You're looking for a mutable string of some kind. There are a lot of ways to create a class that behaves the way you want it.
The easiest way would be to use a StringBuilder object instead of a string. You just have to be careful to not make new StringBuilder objects, but rather alter the existing one. Depending on what you need, this may not be the best option.
Alternatively you can create your own wrapper class for String that you can manipulate freely. The downside is you may have to write a lot of stub methods that call down to the inner string depending on how you want to use it. It would be easier to just expose a read/write string property. This has the advantage of letting you define exactly what behaviours you want, but will take longer to write in the first place. Again, you'll have to make sure to not create new instances of the wrapper class, but rather just alter the class's internal string.
Wrap your string into a custom class, this will allow you to share it amongst a number of different locations. You could also choose to store Char arrays instead.
As a side note (like several have mentioned), if you're doing some heavy processing with strings, use the StringBuilder class. Because of the immutable nature of strings, changing/concatenation of them in loops or what have you - will cause a lot of overhead.
StringBuilder is your friend.

Categories