ag = logss_EventAnalyzer.tabEventsString[0];
ag is a static string,
logss_EventAnalyzer is a class,
tabEventString is a static string array.
During debugging, I saw that logss_EventAnalyzer.tabEventsString[0] contains some string, but it is not assigning into ag. It's value is null.
What is the problem here and what is the solution ?
Thanks !
You say "during debugging"; does logss_EventAnalyzer.tabEventsString[0] contain a (non-null) string when you assign ag?
Note that the assignment doesn't mean that changes to tabEventsString[0] will be reflected in ag, since string is immutable, and any changes to tabEventsString[0] are actually creating new strings. If you want this type of behaviour, you'll need to use a member of some class:
public class Foo {
public string Bar {get;set;}
}
static Foo ag;
static Foo[] tabEventsString;
...
ag = logss_EventAnalyzer.tabEventsString[0];
...
now ag.Bar will always be the same as tabEventsString[0].Bar
Also - do you perhaps have a local variable called ag? This would take precedence.
Can you post code that demonstrates this problem happening?
As an aside; note that both static fields and arrays have various associated complexities if your app gets complex... you might want to consider re-factoring them.
The following works fine:
static class logss_EventAnalyzer {
static string[] tabEventsString = {"abc","def","ghi"};
static string ag;
static void Main() {
ag = logss_EventAnalyzer.tabEventsString[0];
System.Console.WriteLine(ag);
}
}
If you are doing something radically different, you're going to have to give us a clue...
When you have a breakpoint at the line in question, does ag get a value assigned?
I suspect that in some other part of your code you're setting ag to null unintentionally, or perhaps you're assigning ag before logss_EventAnalyzer.tabEventsString[0] is given a non-null value.
If you give more details, I can give a better answer.
The first entry of logss_EventAnalyzer.tabEventsString is containing a string assigned to a null value. You have to look at the stacktrace to see which object is added as 1st entry. This object could be null assigned.
Related
In this fiddle, we are assigning a static field to an instance field. When we change the static one, the instance one still has the initial value. Why is that? We thought that both should be referring to the same object but it seems that they're not.
using System;
public class Program
{
public static string StaticString;
public string InstanceString;
public static void Main()
{
Program.StaticString = "foo";
var p = new Program();
p.InstanceString = Program.StaticString;
Program.StaticString = "bar";
Console.WriteLine(p.InstanceString);
}
}
We were really expecting this to print bar but it printed foo.
In this fiddle, we are assigning a static field to an instance field.
Right. That copies the current value of the static field to the instance field. It doesn't tie the variables together forever - it just copies the current value.
When we change the static one, the instance one still has the initial value.
Yes, because you've just changed the value of the static field - why would that change the value of the instance field? They're independent variables - they just happened to hold the same value at one point. Importantly, you haven't made any change to the string object that the value of the instance field refers to. (And indeed you can't make changes to the string object, because strings are immutable.)
I view variables as being like pieces of paper with the values written on them. When the variable is a reference type, the value on the piece of paper is just a way of navigating to an object - like a street address. But copying one variable to another is always just a matter of copying what's written on one piece of paper onto another. So for example, suppose I have:
House x = new House();
House y = x;
x.DoorColor = Black;
x = null;
Console.WriteLine(y.DoorColor);
That's like:
Creating a piece of paper called x, and writing a street address on it
Copying what's written on piece of paper x onto a piece of paper called y
Going to the house whose address is written on piece of paper x and painting the door black
Rubbing out the address written on piece of paper x
Going to the house whose address is written on piece of paper y and reporting the colour of the door
That last step would report that the door is black, right? Rubbing out the value written on piece of paper x doesn't change either what's written on piece of paper y, or anything about the house.
This isn't quite the same set of steps as in your code, but hopefully it will shed more light on it...
When you assign StaticString to instance string in the statement below
p.InstanceString = Program.StaticString;
The runtime will actually point InstanceString to the string "foo" not to StaticString so when you assign StaticString value bar, runtime will create a string "bar" and point the static string to it. Note Instance string is still point to memory location where we have foo.
I think it will be more easy to understand with the help of a diagram. That shows how StaticString and InstanceString are actually point to values.
You print p.InstanceStringwhich two lines before you set to foo. So it should print foo as it does.
I confused changing the value of a variable with mutating the object at which a reference points.
The fact that strings are immutable of course complicates matters. b = "foo" is really the same as b = new string("foo".ToCharArray()). We're creating a new object and assigning its reference to b. We are not mutating the existing object.
Here is an example that clarifies my mistake.
using System;
using System.Text;
public class Program
{
public static StringBuilder StaticString;
public StringBuilder InstanceString;
public static void Main()
{
Program.StaticString = new StringBuilder("foo");
var p = new Program();
p.InstanceString = Program.StaticString;
Console.WriteLine("Mutating the object at which a value points:");
Program.StaticString.Append("bar");
Console.WriteLine(p.InstanceString);
Console.WriteLine(Program.StaticString);
Console.WriteLine("\nChanging the value of a variable:");
Program.StaticString = new StringBuilder("raboof");
Console.WriteLine(p.InstanceString);
Console.WriteLine(Program.StaticString);
}
}
Output
Mutating the object at which a value points:
foobar
foobar
Changing the value of a variable:
foobar
raboof
This below code compiles and works out as intended.
class MyClass1
{
public void test()
{
string one = "testString1";
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //again testString1 is printed.
}
}
class MyClass2
{
public void test(string two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two = "pilot";
Console.WriteLine(two);
}
}
all I infer from this is:
The value assigned to the string in test method is local to that function and the changes will be reflected only if I use a ref or out.
The question is:
We all know that the string is a reference type (because it is of type, String)
So, for all the reference types : when passing around their objects, the changes should be reflected right ? (For ex, for the same example, if I pass around a object of a class, then any changes are reflected back right ?)
Why is this rule not followed here ?
Can any one point me in understanding what happens under the hood ?
Although strings are reference objects, they are also immutable. Since references are passed by value *, changes to variables representing the reference, are not reflected on the original.
To demonstrate the effect of passing reference objects, replace string with StringBuilder, and change the content inside the test method:
class MyClass1
{
public void test()
{
StringBuilder one = new StringBuilder("testString1");
Console.WriteLine("MyClass1: " + one);
new MyClass2().test(one);
Console.WriteLine(one); //testString1pilot is printed.
}
}
class MyClass2
{
public void test(StringBuilder two)
{
Console.WriteLine("Test method");
Console.WriteLine(two);
two.Append("pilot");
Console.WriteLine(two);
}
}
* Unless the method specifies a different mode of parameter passing, e.g. out or ref.
So, for all the reference types : when passing around their objects,
the changes should be reflected right ?
All reference types are passed by reference is not true.
all reference type or value types are passed by value by default.
if you want to pass any type as reference types you need to use ref or out keyword.
Note: String is a immutable type means Strings can not be changed.
That is the reason why you are not able to see the changes made in the called function.
You need to use StringBuilder to get back the changes.
JonSteek has explained about Parmeter passing well here
In your example, the fact that String is a reference type does not matter. The exact same thing would happen with any value type or even a mutable reference type (like a class).
This is because the parameter to a method normally acts like a local variable within the method. Changes made to the parameter are local to the method.
As you stated, the exception is when the parameter is ref or out.
You have to understand the difference between the string which is a reference type and the variable itself that points to that object.
two = "pilot";
When you do this, you are creating a new string object and telling variable two to now point to this new string. The variable one still points to the original string, which is a different object.
Ok so I have the code below, technically all it does is read the db.txt file line by line and then its suppose to split the line 0 into an array called password.
private string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
private string[] password = lines[0].Split(' ');
but I get the error:
A field initializer cannot reference the non-static field, method, or property
Have a think about what the above means and how you want to populate those variables. You'd need to first construct the class they are a member of, and then hope the lines of code get executed in the order you want them to, and that they don't throw an exception.
The compiler is effectively telling you this isn't the right way to do things.
A better way is to simply write a function to do what you want:
private string[] PasswordLines(){
string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
return lines[0].Split(" ");
}
You can then call this from anywhere you wanted to; for example:
public class MyClass()
{
private string[] Lines
{
get { return PasswordLines(); }
}
private string[] PasswordLines(){
string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
return lines[0].Split(" ");
}
}
C# does not guarantees any specific order of execution when it comes to filed initialization.
For instance these two lines of code will produce undefined results:
private int a = b + 1;
private int b = a + 1;
in theory, the two possible outcomes are a=1,b=2 or a=2,b=1, but in fact it's even worst. We don't even know if a and b are initialized to their default values yet (0 in case of int), so it can be anything (just like a reference to uninitialized object).
To avoid this impossible-to-solve scenario, the compiler demands that all field initializations will be "run-time constants" (return the same value every time, whenever they are executed and independent of any other non "run-time constant" variables).
Just use the constructor when you initialize compound fields and life will be sweet again.
Exactly what is says! Those are (instance) field initializers, and cannot reference each other. Move the code to the constructor instead, or make them method variables instead of fields.
The error is self explanatory.
you can't do this because lines and password both are field variables and you can't assign
one of them value to other(if it's a static then you can).
i hope you are using this code inside a class so until unless an object is not create their no such real existence of these field variables so you can't assign them to each other.
I had a need for a method that could take a collection of strings, and replace all occurrences of a specific string with another.
For example, if I have a List<string> that looks like this:
List<string> strings = new List<string> { "a", "b", "delete", "c", "d", "delete" };
and I want to replace "delete" with "", I would use this LINQ statement:
strings = (from s in strings select (s=="delete" ? s=String.Empty : s)).ToList();
and it works great. But then I figured I should make it an extension method, since I'd likely use it again later. In this case, I just want to write the following:
strings.ReplaceStringInListWithAnother( "delete", String.Empty);
While my code compiles, and the LINQ statement works inside of the extension method, when I return the collection reverts back to its original contents:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
my_list = (from s in my_list select (s==to_replace ? s=replace_with : s)).ToList();
}
So it would seem that I just modified a copy of the List... but when I looked at the code for Pop, it modifies the collection similarly, yet the changes stick, so my assumption was that my method's parameter declarations are correct.
Can anyone explain what I am doing wrong here?
The LINQ statement you wrote does not modify the collection, it actually creates a new one.
The extension method you wrote creates this new collection and then discards it. The assignment is redundant: you’re assigning to a local parameter, which goes out of scope immediately after.
When you’re calling the method, you’re also discarding its result instead of assigning it back.
Therefore, you should write the method like this:
public static List<string> ReplaceStringInListWithAnother(
this List<string> my_list, string to_replace, string replace_with)
{
return (from s in my_list select
(s == to_replace ? replace_with : s)).ToList();
}
and the call like this:
strings = strings.ReplaceStringInListWithAnother("delete", "");
By the way, you can make the function more useful by making it generic:
public static List<T> ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return (from s in my_list select
(s.Equals(to_replace) ? replace_with : s)).ToList();
}
This way you can use it for other things, not just strings. Furthermore, you can also declare it to use IEnumerable<T> instead of List<T>:
public static IEnumerable<T> ReplaceItems<T>(this IEnumerable<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return from s in my_list select (s.Equals(to_replace) ? replace_with : s);
}
This way you can use it for any collection of equatable items, not just List<T>. Notice that List<T> implements IEnumerable<T>, so you can still pass a List into this function. If you want a list out, simply call .ToList() after the call to this one.
Update: If you actually want to replace elements in a list instead of creating a new one, you can still do that with an extension method, and it can still be generic, but you can’t use Linq and you can’t use IEnumerable<T>:
public static void ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
for (int i = 0; i < my_list.Count; i++)
if (my_list[i].Equals(to_replace))
my_list[i] = replace_with;
}
This will not return the new list, but instead modify the old one, so it has a void return type like your original.
Here's a hint: what do you expect the below code to do?
void SetToTen(int y)
{
y = 10;
}
int x = 0;
SetToTen(x);
Hopefully, you understand that the SetToTen method above does nothing meaningful, since it only changes the value of its own local variable y and has no effect on the variable whose value was passed to it (in order for that to happen, the y parameter would have to be of type ref int and the method would be called as SetToTen(ref x)).
Keeping in mind that extension methods are really just static methods in fancy clothes, it should be clear why your ReplaceStringInListWithAnother is not doing what you expected: it is only setting its local my_list variable to a new value, having no effect on the original List<string> passed to the method.
Now, it's worth mentioning that the only reason this is not working for you is that your code works by setting a variable to a new object*. If you were to modify the List<string> passed to ReplaceStringInListWithAnother, everything would work just fine:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
for (int i = 0; i < my_list.Count; ++i)
{
if (my_list[i] == to_replace)
{
my_list[i] = replace_with;
}
}
}
It's also worth mentioning that List<string> is an overly restrictive parameter type for this method; you could achieve the same functionality for any type implementing IList<string> (and so I'd change the my_list parameter to be of type IList<string>).
*Reading your question again, it seems clear to me that this is the main point of confusion for you. The important thing you have to realize is that by default, everything in C# is passed by value. With value types (anything defined as a struct -- int, double, DateTime, and many more), the thing that's passed is the value itself. With reference types (anything that's defined as a class), the thing that's passed is a reference to an object. In the latter case, all method calls on references to objects of mutable types do actually affect the underlying object, since multiple variables of reference type can point to the same object. But assignment is different from a method call; if you assign a reference to an object that has been passed by value to some new reference to an object, you are doing nothing to the underlying object, and therefore nothing is happening that would be reflected by the original reference.
This is a really important concept that many .NET developers struggle with. But it's also a topic that's been explained thoroughly elsewhere. If you need more explanation, let me know and I'll try to dig up a link to a page that makes all of this as clear as possible.
You haven't shown the code for "Pop" so it's hard to know what you mean. You talk about "when I return the collection" but you're not returning anything - the method has a void return type.
LINQ typically doesn't change the contents of an existing collection. Usually you should return a new collection from the extension method. For example:
public static IEnumerable<string> ReplaceAll
(this IEnumerable<string> myList, string toReplace, string replaceWith)
{
return toReplace.Select(x => x == toReplace ? replaceWith : x);
}
(I've made it more general here - you shouldn't start materializing lists unless you really need to.)
You'd then call it with:
strings = strings.ReplaceAll("delete", "").ToList();
... or change the type of string to IEnumerable<string> and just use
strings = strings.ReplaceAll("delete", "");
I want to write a 'Date' class that behaves like a Value Type.
for example, Instead of writing a Clone method for setting properties safely, make the Date class to pass by value:
public Date Birthday
{
get { return this.birthday; }
set
{
this.birthday = value.Clone();
} //I want to write this.birthday = value;
//without changing external value when this.Birthday changes
}
I know this is possible because System.String is a class and behaves like a value. for example:
String s1 = "Hello";
String s2 = "Hi";
s1 = s2;
s2="Hello";
Console.WriteLine(s1); //Prints 'Hi'
First I thought writers of this class override '=' operator, but now I know that the '=' operator can not be overridden. so how they write String class?
Edit: I just want to make my Date class to pass it's instances by value, like as String.
First, your string-based example does not illustrate your question.
The thing with DateTime and String is that they are immutable: once an instance is created, it cannot be changed in any way. For example, you cannot add 2 minutes to a DateTime instance by just saying date.Minutes += 2: you'll have to invoke date.AddMinutes(2), which will yield a totally new instance.
To make objects read-only, just follow the same pattern.
public class Date{ ...code...} would be a reference type...not what you want.
public struct Date { ...code...} would be a value type...probably what you want.
The string class is, as it is a class, a reference type...and is immutable..how being immutable effects the behavior of string objects can be confusing at the start.
Given string s1 = "Fish"; s1 is a reference that points to "Fish"...It is the "Fish" bit can never be changed....what s1 points to can be changed. If you then assign s1 = "Tuna"; "Fish" still exists but is no longer referenced and will be GC'd.
In your example after: s1=s2 s1,s2 now reference the same string "Hi"...there is only one "Hi".
I hope I have not gone way below your level.
It's not the '=' operator, it's the fact that when you say
stringThing = "thing";
you're creating a new string, not changing the current string to something else.