I have created a generic type to act as a pointer so that I can pass by reference. (Perhaps there is a much more simple way of doing this but I want to stress that I am doing this to learn more about generics and passing by reference, not the most efficient way of completing the task, if that makes sense.)
Here is the code I wrote for the generic type
class GenericPointer<T> {
public T item;
public void setItem(T i){ item = i; }
public T getItem(){ return item; }
}
In my program I have created an instance of this type called 'intPointer'. The value 143 is arbitrary.
GenericPointer<int> intPointer = new GenericPointer<int>();
intPointer.setItem(143);
Console.WriteLine(intPointer.getItem());
The above code runs properly, setting and returning the value 143.
I now want to pass this 'intPointer' to a method that increments it and then prints the value again.
So I wrote a method called addone()
public void addone(int i) { i ++; }
Now I want to make the following calls (remembering that I already set the value to 143):
Console.WriteLine(intPointer.getItem());
addone(intPointer);
Console.WriteLine(intPointer.getItem());
What I was expecting to see was 143 then 144 however I get the following errors:
The best overloaded method match for 'Notes.Program.addone(int)' has some invalid arguments
and:
cannot convert from 'Notes.GenericPointer<int>' to 'int'
Any help would be greatly appreciated!
I'll begin by correcting some of your terminology: you're not using pointers. C# does support pointers, but using the unsafe keyword, and they are real pointers (as in, integer memory addresses you can directly manipulate). The code you written is just an example of a boxed object.
.NET supports boxing already, by casting to Object; however it isn't recommended nor needed because the ref keyword solves the problem you're trying to "fix".
Use the ref keyword to describe a value-type parameter that should be passed by-reference instead of by-value. All other semantics remain the same, like so:
void Foo() {
int x = 123;
Bar(ref x);
Console.Write( x ); // prints "124".
}
void Bar(ref int x) {
x++;
}
I have a few other notes:
C# and .NET conventions dictate that all public members (methods, properties, fields, etc) should have TitleCase, not camelCase (i.e. ensure the first letter is capitalised).
Trivial getter and setter methods are discouraged, used Properties instead (though I note you cannot use ref arguments with properties).
You're getting your error because the type of intPointer is not int, but your class GenericPointer<int>.
While GenericPointer is wrapping an int, it is not actually an int so it cannot be treated as one. It has properties that are an int.
Imagine if GenericPointer wrapped a string. What would AddOne do to that.
You can act on the properties of the class but not treat the entire class as its generic type.
It would be possible to write an AddOne method that took a Generic Pointer argument and then inspected it for intyness and then added one to the internal item if it was an int. I am sure that is not a good idea.
What are you really trying to achieve with this GenericPointer?
If you want parameters to be reference if they are a value type (string, int, bool, etc.) then make your parameter like this:
public void addone(ref int i)
{
i++;
}
Then call the method like so:
addone(ref variableInt);
You can also look at this in order to see how to make your classes work as a specific type.
Related
Quick question.
In the second example on this documentation page (the second code block, featuring a method called CompareDinosByLength), the Sort method is called as such:
dinosaurs.Sort(CompareDinosByLength);
Why is it that the Sort method didn't need an explicitly declared delegate, as I would have thought by reading the Delegate documentation? Before I found that example, I was attempting to do it like so:
delegate int CompareDinosDel(string first, string second);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
But I kept getting errors related to the delegate / delegate method not being proper Comparers.
Shouldn't both work?
Why is it that the Sort method didn't need an explicitly declared delegate?
C# permits a method group -- that is, a method which is named without having the (...) argument list to invoke it -- to be used in a context where a delegate is expected. The compiler performs overload resolution on the method group as though the method group had been invoked with arguments of the types of the delegate's formal parameters. This determines which method of the method group should be used to create the delegate.
This overload resolution process can sometimes lead to unusual situations involving method type inference when the method group is undergoing overload resolution to a delegate type which is a formal parameter type of a generic method; Sort, fortunately is not a generic method, so these oddities do not come into play.
This feature was added to C# 2.0; before that a method group had to be converted to a delegate via
new MyDelegate(MyMethod)
I keep getting errors related to the delegate / delegate method not being proper Comparers. Shouldn't both work?
Unfortunately, no. C# does not have structural identity on delegate types. That is:
delegate void Foo();
delegate void Bar();
...
Foo foo = ()=>{};
Bar bar = foo; // ERROR!
Even though Foo and Bar are structurally identical, the compiler disallows the conversion. You can however use the previous trick:
Bar bar = foo.Invoke;
This is equivalent to
Bar bar = new Bar(foo.Invoke);
However the new bar has as its action to invoke foo; it goes through a level of indirection.
This feature does make some sense.
Reason one:
You don't expect structural identity to work in other places:
struct Point { int x; int y; ... }
struct Pair { int key; int value; ... }
....
Point point = whatever;
Pair pair = point; // ERROR
Reason two:
You might want to say:
delegate int PureMethod(int);
And have a convention that PureMethod delegates are "pure" -- that is, the methods they represent do not throw, always return, return a value computed only from their argument, and produce no side effects. It should be an error to say
Func<int, int> f = x => { Console.WriteLine(x); return x+1; };
PureMethod p = f;
Because f is not pure.
However in hindsight people do not actually make semantics-laden delegates. It is a pain point that a value of type Predicate<int> cannot be assigned to a variable of type Func<int, bool> and vice versa.
If we had to do it all over again, I suspect that delegates would have structural identity in the CLR.
Finally, I note that VB is much more forgiving about inter-assigning mixed delegate types; it automatically builds an adapter delegate if it needs to. This can be confusing because sometimes it looks like referential identity is maintained when in fact it is not, but this is in keeping with the VB philosophy of "just make my code work".
dinosaurs.Sort(CompareDinosByLength);
CompareDinosDel newDel = CompareDinosByLength;
dinosaurs.Sort(newDel);
Shouldn't both work?
No, because you are passing two very different things into those two function calls.
The key here is to recognize that, in both cases, what you actually pass into the method is a delegate. In the first case, the compiler is implicitly creating a delegate of the correct type for you, even though you didn't explicitly ask it to. In the second case, you're making your own delegate, but it's the wrong type, so that attempt will fail.
Starting with .NET 2.0, the C# compiler allow you to skip explicitly create delegates in many situations. If you use a method name in a context where a delegate is expected, and the compiler can verify that the method signature and delegate signature match, it will implicitly construct a delegate instance using the method. That is, instead of doing this (the "old" way)
this.SubmitButton.Click += new System.EventHandler(this.SubmitButton_Click);
You can now do this:
this.SubmitButton.Click += this.SubmitButton_Click;
Visual Studio itself will still generate the older syntax, I assume because it still works and because it's not worth the developer's time to go messing around with it for very little benefit. However, most popular code analysis tools will flag the redundant delegate creation if you use it in your own code.
This same technique works anywhere you have a method (technically a "method group", since one method name can refer to more than one overload), and you assign it to a variable of a delegate type. Passing a method as a parameter into another method is the same type of assignment operation: you are "assigning" the actual parameter at the call site to the formal parameter in the method body, so the compiler does the same thing. In other words, the following two method calls do exactly the same thing:
dinosaurs.Sort(CompareDinosByLength);
dinosaurs.Sort(new Comparison<string>(CompareDinosByLength));
Your unsuccessful attempt to make a delegate, on the other hand, did something slightly different:
dinosaurs.Sort(new CompareDinosDel(CompareDinosByLength));
This time, you told the compiler exactly what kind of delegate you wanted, but that's not the kind of delegate that the method expected. In general, the compiler isn't going to try to second guess what you told it do to; if you ask it to do something that looks "fishy", it will produce an error (in this case, a type mismatch error).
This behavior is similar to what would happen if you tried to do this:
public class A
{
public int x;
}
public class B
{
public int x;
}
public void Foo(A a) { }
public void Bar()
{
B b = new B();
this.Foo(b);
}
In this case, A and B are two distinct types, even though their "type signature" is exactly the same. Any line of code that works on an A will also work equally well on a B, but yet, we cannot use them interchangeably. Delegates are types like any other types, and C#'s type safety rules require that we use the correct delegate types where we need them, and can't get away with just using a close enough type.
The reason this is a good thing is because a delegate type may have a lot more meaning that just it's technical components would imply. Like any other data type, when we create delegates for our applications, we usually apply some kind of semantic meaning to those types. We expect, for example, that if we have a ThreadStart delegate, that it's going to be associated with a method that runs when a new thread starts. the delegate's signature is about as simple as you get (no parameters, no return value) but the implication behind the delegate is very important.
Because of that, we generally want the compiler to tell us if we try to use the wrong delegate type in the wrong place. More often than not, that's probably a sign that we are about to do something that may compile, and even run, but is likely to do the wrong thing. That's never something you want from your program.
While all that is true, it's also true that often times you really don't want to assign any semantic meaning to your delegates, or else, the meaning is assigned by some other part of your application. Sometimes you really do just want to pass around an arbitrary piece of code that has to run later. This is very common with functional-style programs or asynchronous programs, where you get things like continuations, callbacks, or user-supplied predicates (look at the various LINQ methods, for example). .NET 3.5 and onward supply a very useful set of completely generic delegates, in the Action and Func family, for this purpose.
Consider the following code:
public class Foo
{
public int Bar { get; set; }
}
public class SomeOtherFoo
{
public int Bar { get; set; }
}
Should I be able to say:
Foo foo = new SomeOtherFoo();
That won't work in C# either. When you have two different types that have the same body/implementation, they are still different types. Two classes with the same properties are still different classes. Two different delegates with the same signature are still different delegates.
The Sort method has already defined the delegate type, and you need to match it. This is very much like it defining a class that it needs to accept as a parameter; you can't just pass in another type with the same properties and methods.
This is what it means for a language to be statically typed. An alternate type system would be to use "Duck Typing" in which the language doesn't apply the constraint that a variable be of a specific type, but rather that it has a specific set of members. In other words, "If it walks like a duck, and quacks like a duck, pretend it's a duck." That is opposed to the style of typing that says, "It must be a duck, period, even if it knows how to walk and quack."
I need to write a bunch of methods that take 1..N generic type parameters, eg:
int Foo<T1>();
int Foo<T1,T2>();
int Foo<T1,T2,T3>();
...
int Foo<T1,T2,T3...TN>();
Inside Foo() I would like to do something for each type, eg
int Foo<T1,T2,T3>() {
this.data = new byte[3]; // allocate 1 array slot per type
}
Is there any way to parameterize this so that I am not editing every variation of Foo(), something analogous to:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
}
Ideally, I'd also like to be able to get an array or collection of the types as well:
int Foo<T1,T2,T3>() {
this.data = new byte[_NUMBER_OF_GENERIC_PARAMETERS];
// can do this
Type [] types = new Type[] { T1, T2, T3 };
// but would rather do this
Type [] types = _ARRAY_OR_COLLECTION_OF_THE_GENERIC_PARAMETERS;
}
You can read the current generic parameters and their number from the MethodInfo.GetGenericArguments array.
You can retrieve the MethodInfo for your current method by using the MethodBase.GetCurrentMethod method.
Note that you will still need to supply several generic overloads of your method with different numbers of generic parameters, as C# and the CLI do not support variadic generic parameter lists.
So, your code sample for the method with three generic parameters could be written like this:
int Foo<T1,T2,T3>() {
MethodInfo mInfo = (MethodInfo)MethodBase.GetCurrentMethod();
Type[] types = mInfo.GetGenericArguments();
this.data = new byte[types.Length];
}
1) You can get the number of template arguments via reflection: http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx . This way, you can have common implementation for each Foo. In each Foo you can just call:
FooImpl();
The only difference (regarding the "GetCurrentMethod") is that you'll need to get method info of the previous method:
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
2) You could generate all Foo versions at runtime - all would share the same implementation of calling FooImpl only. Some details on generating methods at runtime: Creating a function dynamically at run-time and here: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx
The .NET framework regards a generic class or method with N type parameters as having a different name from one having more or fewer. It would probably be possible without a huge change to the framework to arrange things so that calling a function
foo<T>(autogeneric ref T it)
as:
foo(1, "George", 5.7);
would get translated as to:
struct foo99 {public int p1; public string p2; public double p3};
...
foo99 temp99;
temp99.p1 = 1;
temp99.p2 = "George";
temp99.p3 = 5.7;
foo1(ref temp);
That would allow a generic method to efficiently accept an arbitrary number of parameters. Being able to pass such anonymous structure by ref might not seem terribly useful, but it could be very powerful when combined with lambdas.
Normally, closing over local variables in a lambda expression would require hoisting the local variables to a heap object and building a delegate which targets that heap object. If one could use the above style, one could instead of creating a persistent closure object and a delegate and passing the delegate, simply hoist the appropriate variables to a structure and pass a byref to it along with a static delegate. This would only work in cases where the called routine wouldn't have to persist the passed-in closure, but on the flip side the caller would know that the called routine wouldn't be persisting the closure. Further, while no .NET languages would support such a thing and some framework changes might be required to allow code which did this to be volatile, passing by reference a structure some of whose members were also byrefs could make it possible for a lambda to access the enclosing procedure's ref parameters--something which is presently not possible (since there's no guarantee the created delegate wouldn't outlive the scope where it was created). Structures die when the scope they're in dies, so the problem wouldn't have to exist with them.
I wish .NET languages had a convenient way of expressing these concepts. The fact that closures can cause variables' lifetimes to be arbitrarily persisted means that code which has ever used a variable in a closure must assume that outside code could change it at any time. A struct-based approach wouldn't have that issue.
No.
You can not use the Type parameter as you want. But you could use something like Tuple. It allows you to Wrap generics. But you can not use the TypeParamter itself.
I was looking at this question, and aside from a rather odd way to enumerate something, the op was having trouble because the enumerator is a struct. I understand that returning or passing a struct around uses a copy because it is a value type:
public MyStruct GetThingButActuallyJustCopyOfIt()
{
return this.myStructField;
}
or
public void PretendToDoSomething(MyStruct thingy)
{
thingy.desc = "this doesn't work as expected";
}
So my question is if MyStruct implements IMyInterface (such as IEnumerable), will these types of methods work as expected?
public struct MyStruct : IMyInterface { ... }
//will caller be able to modify the property of the returned IMyInterface?
public IMyInterface ActuallyStruct() { return (IMyInterface)this.myStruct; }
//will the interface you pass in get its value changed?
public void SetInterfaceProp(IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
Yes, that code will work, but it needs explanation, because there is a whole world of code that will not work, and you're likely to trip into that unless you know this.
Before I forget: Mutable structs are evil. OK, with that out of the way, let's move on.
Let's take a simple example, you can use LINQPad to verify this code:
void Main()
{
var s = new MyStruct();
Test(s);
Debug.WriteLine(s.Description);
}
public void Test(IMyInterface i)
{
i.Description = "Test";
}
public interface IMyInterface
{
string Description { get; set; }
}
public struct MyStruct : IMyInterface
{
public string Description { get; set; }
}
When executing this, what will be printed?
null
OK, so why?
Well, the problem is this line:
Test(s);
This will in fact box that struct and pass the boxed copy to the method. You're successfully modifying that boxed copy, but not the original s variable, which was never assigned anything, and is thus still null.
OK, so if we change just one line in the first piece of code:
IMyInterface s = new MyStruct();
Does this change the outcome?
Yes, because now you're boxing that struct here, and always use the boxed copy. In this context it behaves like an object, you're modifying the boxed copy and writing out the contents of the boxed copy.
The problem thus crops up whenever you box or unbox that struct, then you get copies that live separate lives.
Conclusion: Mutable structs are evil.
I see two answers about using ref here now, and this is barking up the wrong tree. Using ref means you've solved the problem before you added ref.
Here's an example.
If we change the Test method above to take a ref parameter:
public void Test(ref IMyInterface i)
Would this change anything?
No, because this code is now invalid:
var s = new MyStruct();
Test(ref s);
You'll get this:
The best overloaded method match for 'UserQuery.Test(ref UserQuery.IMyInterface)' has some invalid arguments
Argument 1: cannot convert from 'ref UserQuery.MyStruct' to 'ref UserQuery.IMyInterface'
And so you change the code to this:
IMyInterface s = new MyStruct();
Test(ref s);
But now you're back to my example, just having added ref, which I showed is not necessary for the change to propagate back.
So using ref is orthogonal, it solves different problems, but not this one.
OK, more comments regarding ref.
Yes, of course passing a struct around using ref will indeed make the changes flow throughout the program.
That is not what this question was about. The question posted some code, asked if it would work, and it would. In this particular variant of code it would work. But it's so easy to trip up. And pay particular note that the question was regarding structs and interfaces. If you leave interfaces out of it, and pass the struct around using ref, then what do you have? A different question.
Adding ref does not change this question, nor the answer.
Within the CLR, every value-type definition actually defines two kinds of things: a structure type, and a heap object type. A widening conversion exists from the structure type to the boxed object type, and a narrowing conversion exists from Object to the structure type. The structure type will behave with value semantics, and the heap object type will behave with mutable reference semantics. Note that the heap object types associated with all non-trivial structure types [i.e. those with any non-default states] are always mutable, and nothing in the structure definition can cause them to be otherwise.
Note that value types may be constrained, cast, or coerced to interface types, and cast or coerced to reference types. Consider:
void DoSomethingWithDisposable<T,U>(ref T p1,
List<int>.Enumerator p2) where T:IDisposable
{
IDisposable v1a = p1; // Coerced
Object v1b = p1; // Coerced
IDisposable v2a = (IDisposable)p2; // Cast
Object v2b = (Object)p2; // Cast
p1.Dispose(); // Constrained call
}
void blah( List<string>.Enumerator p1, List<int>.Enumerator p2) // These are value types
{
DoSomethingWithDisposable(p1,p2); // Constrains p1 to IDisposable
}
Constraining a generic type to an interface type does not affect its behavior as a value type. Casting or coercing an a value type to an interface or reference type, however, will create a new instance of the heap object type and return a reference to that. That reference will then behave with reference-type semantics.
The behavior of value types with generic constraints can at times be very useful, and such usefulness can apply even when using mutating interfaces, but unfortunately there's no way to tell the compiler that a value type must remain as a value type, and that the compiler should warn if it would find itself converting it to something else. Consider the following three methods:
bool AdvanceIntEnumerator1(IEnumerator<int> it)
{ return it.MoveNext(); }
bool AdvanceIntEnumerator2(ref T it) where T:IEnumerator<int>
{ return it.MoveNext(); }
bool AdvanceIntEnumeratorTwice<T>(ref T it) where T:IEnumerator<int>
{ return it.MoveNext() && AdvanceIntEnumerator1(it); }
If one passes to the first piece of code a variable of type List<int>.Enumerator, the system will copy its state to a new heap object, call MoveNext on that object, and abandon it. If one passes instead a variable of type IEnumerator<int> which holds a reference to a heap object of type List<int>.Enumerator, it will call MoveNext on that instance, which the calling code will still retain.
If one passes to the second piece of code a variable of type List<int>.Enumerator, the system will call MoveNext on that variable, thus changing its state. If one passes a variable of type IEnumerable<T>, the system will call MoveNext on the object referred to by that variable; the variable won't be modified (it will still point to the same instance), but the instance to which it points will be.
Passing to the third piece of code a variable of type List<int>.Enumerator will cause MoveNext to be called on that variable, thus changing its state. If that returns true, the system will copy the already-modified variable to a new heap object and call MoveNext on that. The object will then be abandoned, so the variable will only be advanced once, but the return value will indicate whether a second MoveNext would have succeeded. Passing the third piece of code a variable of type IEnumerator<T> which holds a reference to a List<T>.Enumerator, however, will cause that instance to be advanced twice.
No, interface is a contract, to make it work properly you need to use ref keyword.
public void SetInterfaceProp(ref IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
What matters here is a real type that stays inside that interface wrap.
To be more clear:
even if code with method SetInterfaceProp defined like
public void SetInterfaceProp(IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
will work:
IMyInterface inter= default(MyStruct);
SetInterfaceProp(inter);
this one will not :
MyStruct inter = default(MyStruct);
SetInterfaceProp(inter);
You can not gurantee that the caller of your method will always use IMyInterface, so to guarantee expected behavior, in this case, you can define ref keyword, that will guarantee that in both cases method would run as expected.
I'm trying to do
myDic.TryGetValue("username", out user.Username);
but its not working.
is this not possible?
No, from the documentation:
"Properties are not variables and therefore cannot be passed as out parameters."
http://msdn.microsoft.com/en-us/library/t3c3bfhx.aspx
To continue John's answer, do this instead:
string username;
if (myDic.TryGetValue("username", out username))
{
user.Username = username;
}
You could do this in VB, but not C#.
VB will generate a temporary variable (on the stack), pass in it's address to the out value, and then do an assignment to the property after the method call.
Generally VB does this because it does lots of implicit stuff all over the place. That's just the way it works.
C#, on the other hand, tends to eschew implicitness as part of its philosophy. That's why, for example, you have to add "out" to the call site in order to get out parameters to work, and why it doesn't support "ref" parameters for the first argument to extension methods.
It would be possible to support properties here, using an explicit "out" syntax at the call site. However, I believe the reason they don't do this is because the trick VB uses does not behave exactly the same for properties as it does for fields. With a field, the assignment would take place immediately where it occurred inside the method. If there was other code in the method that read the field (by calling a method on the object), it would read the new field value assigned via the output parameter.
With properties, using the VB trick, the property doesn't get assigned until after the method returns. This means that any code that read the property directly after the out parameter assignment would read the old value.
Here's a simple example of what I mean:
class C
{
private int m_bar;
public int Bar { get { return m_bar; } set { m_bar = value; }}
void foo(out int x)
{
x = 2;
Console.WriteLine(Bar);
}
void DoStuff()
{
foo(out m_bar); //outputs 2
Bar = 0;
//pretend this works
foo(out Bar); //outputs 0
Console.WriteLine(Bar); // outputs 2
}
}
Inside DoStuff(), you would get different behavior for the first call to foo than you would from the second call to foo, although most folks would expect them to behave the same way.
Generally C# tries to avoid these types of things.
That's my guess as to why they don't support it (the spec just says that don't support, it doesn't really say why).
While using keyword ref, calling code needs to initialize passed arguments, but with keyword out we need not do so.
Why don't we use out everywhere?
What is exact difference between the two?
Please give example of a situation in which we need to use ref and can't use out?
The answer is given in this MSDN article. From that post:
The two parameter passing modes
addressed by out and ref are subtly
different, however they are both very
common. The subtle difference between
these modes leads to some very common
programming errors. These include:
not assigning a value to an out
parameter in all control flow paths
not assigning a value to variable
which is used as a ref parameter
Because the C# language assigns
different definite assignment rules to
these different parameter passing
modes, these common coding errors are
caught by the compiler as being
incorrect C# code.
The crux of the decision to include
both ref and out parameter passing
modes was that allowing the compiler
to detect these common coding errors
was worth the additional complexity of
having both ref and out parameter
passing modes in the language.
out is a special form of ref where the referenced memory should not be initialized before the call.
In this case the C# compiler enforces that the out variable is assigned before the method returns and that the variable is not used before it has been assigned.
Two examples where out doesn't work but ref does:
void NoOp(out int value) // value must be assigned before method returns
{
}
void Increment(out int value) // value cannot be used before it has been assigned
{
value = value + 1;
}
None of these answers satisfied me, so here's my take on ref versus out.
My answer is a summary of the following two pages:
ref (C# Reference)
out (C# Reference)
Compare
Both the method definition and the calling method must explicitly use the ref / out keyword
Both keywords cause parameters to be passed by reference (even value types)
However, there is no boxing when a value type is passed by reference
Properties cannot be passed via out or ref, because properties are really methods
ref / out are not considered to be part of the method signature at compile time, thus methods cannot be overloaded if the only difference between them is that one of the methods takes a ref argument and the other takes an out argument
Contrast
ref
Must be initialized before it is passed
Can use to pass a value to the method
out
Does not have to be initialized before it is passed
Calling method is required to assign a value before the method returns
Can not use to pass a value to the method
Examples
Won't compile because only difference in method signatures is ref / out:
public void Add(out int i) { }
public void Add(ref int i) { }
Using ref keyword:
public void PrintNames(List<string> names)
{
int index = 0; // initialize first (#1)
foreach(string name in names)
{
IncrementIndex(ref index);
Console.WriteLine(index.ToString() + ". " + name);
}
}
public void IncrementIndex(ref int index)
{
index++; // initial value was passed in (#2)
}
Using out keyword:
public void PrintNames(List<string> names)
{
foreach(string name in names)
{
int index; // not initialized (#1)
GetIndex(out index);
Console.WriteLine(index.ToString() + ". " + name);
}
}
public void GetIndex(out int index)
{
index = IndexHelper.GetLatestIndex(); // needs to be assigned a value (#2 & #3)
}
Author's Random Remarks
In my opinion, the concept of using the out keyword is similar to using the Output enum value of ParameterDirection for declaring output parameters in ADO.NET
Arrays in C# are passed by reference, but in order for a reassignment of the array reference to affect the reference in the calling code, the ref keyword must be used
Example:
public void ReassignArray(ref int[] array)
{
array = new int[10]; // now the array in the calling code
// will point to this new object
}
For more info on reference types versus value types, see Passing Reference-Type Parameters (C# Programming Guide)
A contrived example of when you'd need to use ref and not out is as follows:
public void SquareThisNumber(ref int number)
{
number = number * number;
}
int number = 4;
SquareThisNumber(ref number);
Here we want number to be an in-out variable, so we use ref. If we had used out, the compiler would have given an error saying we initialized an out param before using it.
The ref keyword allows you to change the value of a parameter. The method being called can be an intermediate link in the calling chain. A method using the out keyword can only be used at the beginning of a calling chain.
Another advantage is that the existing value can be used in the logic of the method and still hold the return value.
In Oracle functions have explicit IN (default and what you get if you don't set a direction) IN/OUT and OUT parameters. The equivalent is normal (just the parameter), ref [parameter], and out [parameter].
The compiler knows that out variables shouldn't set before the call. This allows them be just declared before use. However it knows that it must be set before the function it's used in returns.
When we pass the value while calling the method prefixed by the out keyword, it treats it entirely different like we are not passing it to the method. Instead we are actually collecting (outing) the value of the out variable from the definition section of the method to the method out variable parameter where we are calling that method.
So out variable is the output of processing done with in the method definition, and this is the reason why we need to create it, initialize it, and modify it within the definition only.
An out variable is used when we need return multiple values from a particular method.
While in case of a ref variable we need to initialize it first as its memory location is transfered to method definition as parameter. Think what would happen if we are not initializing it before passing?