Resolved Another issue from a beginner C# programmer.

C# learner

Active member
Joined
Dec 22, 2022
Messages
40
Programming Experience
Beginner
I created a method that uses a value parameter to be used to find a record in a file and out parameters. I learned how to get the out parameters initialized, but having trouble with the first parameter, idIndividualID. I don't want to null the field because the value is used in the if statement to find the correct record. Why is the field highlighted in red? Error says " The name idIndividualID does not exist in the current context".
C#:
 static void FindIndRecord (string idIndividualID, // field in question
                                          out string idSurname,
                                          out string idGivenName,
                                          out string idBirthDate,
                                          out string idBirthPlace,
                                          out string idMarriageDate,
                                          out string idMarriagePlace,
                                          out string idDeathDate,
                                          out string idDeathPlace,
                                          out string idSex,
                                          out string idChildCode,
                                          out string idParentCode)
                             
                {
                   
                    idSurname = null;
                    idGivenName = null;
                    idBirthDate = null;
                    idBirthPlace = null;
                    idMarriageDate = null;
                    idMarriagePlace = null;
                    idDeathDate = null;
                    idDeathPlace = null;
                    idSex = null;
                    idChildCode = null;
                    idParentCode = null;
                }

                {   
                    // While control variable
                    string recordLine;
                   

                    string path = (@"C:\Users\steve\OneDrive\Documents\Donna's Documents\Steves stuff\Family Tree Development Folder\GEDCOM Individual Data.csv");
                    using StreamReader id = new StreamReader(path, true);
                    {
                        while ((recordLine = id.ReadLine()) != null)
                        {
                           
                            // using the split method to parse "line" into lineParts array
                            string[] lineParts = recordLine.Split(',');

                            //string trimIndividualID = null;
                             if (lineParts[1] = idIndividualID  //field in question
                            {
                                string idSurname = (lineParts[2] != null && lineParts[2] != " ") ? lineParts[2] : " ";
                                string idGivenName = (lineParts[3] != null && lineParts[3] != " ") ? lineParts[3] : " ";
                                string idBirthDate = (lineParts[4] != null && lineParts[4] != " ") ? lineParts[4] : " ";
                                string idBirthPlace = (lineParts[5] != null && lineParts[5] != " ") ? lineParts[5] : " ";
                                string idMarriageDate = (lineParts[6] != null && lineParts[6] != " ") ? lineParts[6] : " ";
                                string idMarriagePlace = (lineParts[7] != null && lineParts[7] != " ") ? lineParts[7] : " ";
                                string idDeathDate = (lineParts[8] != null && lineParts[8] != " ") ? lineParts[8] : " ";
                                string idDeathPlace = (lineParts[9] != null && lineParts[9] != " ") ? lineParts[9] : " ";
                                string idSex = (lineParts[10] != null && lineParts[10] != " ") ? lineParts[10] : " ";
                                string idChildCode = (lineParts[11] != null && lineParts[11] != " ") ? lineParts[11] : " ";
                                string idParentCode = (lineParts[12] != null && lineParts[12] != " ") ? lineParts[12] : " ";

                                Array.Clear(lineParts, 0, lineParts.Length);
                                return;
                            }
                           
                        }
                    }
                }
 
Good job trying to use code tags. It looks like that you just accidentally deleted the closing square bracket from the header that forum put in for you.
The code tag was supposed to start looking like:
C#:
[CODE lang="csharp" title="FindIndRecord"] static void FindIndRecord(string idIndividualID,

but you had:
C#:
[CODE lang="csharp" title="FindIndRecord" static void FindIndRecord(string idIndividualID,

I fixed your post for you.
 
Now all the if statement out variables are red underlined.
What's the error message you are getting?

As an aside, never completely rely Intellisense (aka the red squiggly underlines), as good as it has been, it's still not as reliable as actually compiling your code with the compiler.

Anyway, part of the issue maybe that on lines 43-53 you are declaring and initializing new variables which just happen to have the same names as your out variables. Perhaps you actually meant to assign values to your out variables?
 
...beginner C# programmer...

C#:
out this, out that, out theOther, out blah, out ..., out, out, outoutoutout

No, no, no and no

As a beginner you should stay well away from out - Microsoft managed to write nearly the entirely of .net without using it; do not use it

The way to correctly return multiple items of data from a method call, in OO programming, is to orient it objectly and encapsulate it all in a class, an instance of which you return

C#:
//no
void GetPerson(int id, out string name, out int age, out DateTime birthday){
    //look person up by id etc
    name = ...;
    age = ...;
    birthday = ...;
}


//yes
public class Person{
  public string Name {get;set;}
  public int Age {get;set;}
  public DateTime Birthday {get;set;}
}

Person GetPerson(int id){
  //get by id etc
  return new Person(){
    Name = ...,
    Age = ...,
    Birthday = ...
  }
}
 
Doesn't the variables in the class/method declaration and the fields in the if statement have to be the same? Can I define new fields just after the class/method declaration and populate them in the if routine and it will still send the variable values back to the calling method?
 
CJARD, Thank you. I tried using that many parameters with a return statement after the if grouping. I got an error message when I did that. I tried a nested tuple and that didn't work. That's why I went back to the old way of using out. I will go back and look at encapsulation and learn the idea behind it. I thought to a certain extent I was doing so but evidently not.
 
You can only ever return one thing from a method. If you need to return two+ bits of information, you bundle them up into one thing and return that. The one thing can be a class, struct, record, tuple, collection(if all the same type), anonymous type..

..but stick with class for now


To be clear, all these return only one thing:

C#:
public Person GetPersonById(...){
  var p = new Person(){
    Name = ...,
    Age = ...,
    Birthday = ...
  };

  return p;
}

public Person GetPersonById(...){
  return new Person(){
    Name = ...,
    Age = ...,
    Birthday = ...
  };
}

public Person GetPersonById(...) =>
  new Person(){
    Name = ...,
    Age = ...,
    Birthday = ...
  };

The first might appeal because it's obviously returning one thing

The second is shortcutting the first, doing away with the temporary variable

The third is a form you wouldn't really see in this "get by id" context because you probably have to write more than one line of code to get a person by id, but you might see it in simple cases where a method would merely consist of a return statement and nothing else. Here the "=> ..." effectively means "{ return ... }" so it's a slight abbreviation
 
Last edited:
that many parameters with a return statement
So to clarify, a return statement must be proceeded by only one thing, and new Person{ ..., ..., ... } complex and large and verbose and stuffed full of commas as it may be, is only one thing (a Person)
 
Is this any better?:
static void FindIndRecord(string trimIndividualID)
                {

                    

                    string familyRecord;

                    string path = (@"C:\Users\steve\OneDrive\Documents\Donna's Documents\Steves stuff\Family Tree Development Folder\GEDCOM Individual Data.csv");
                    using StreamReader md = new StreamReader(path, true);
                    {
                        while ((familyRecord = md.ReadLine()) != null)
                        {

                            // using the split method to parse "line" into lineParts array
                            string[] familyParts = familyRecord.Split(',');

                            //string trimIndividualID = null;
                            if (familyParts[1] == familyRecord)
                            {
                                string mdSurname = (familyParts[2] != null && familyParts[2] != " ") ? familyParts[2] : " ";
                                string mdGivenName = (familyParts[3] != null && familyParts[3] != " ") ? familyParts[3] : " ";
                                string mdBirthDate = (familyParts[4] != null && familyParts[4] != " ") ? familyParts[4] : " ";
                                string mdBirthPlace = (familyParts[5] != null && familyParts[5] != " ") ? familyParts[5] : " ";
                                string mdMarriageDate = (familyParts[6] != null && familyParts[6] != " ") ? familyParts[6] : " ";
                                string mdMarriagePlace = (familyParts[7] != null && familyParts[7] != " ") ? familyParts[7] : " ";
                                string mdDeathDate = (familyParts[8] != null && familyParts[8] != " ") ? familyParts[8] : " ";
                                string mdDeathPlace = (familyParts[9] != null && familyParts[9] != " ") ? familyParts[9] : " ";
                                string mdSex = (familyParts[10] != null && familyParts[10] != " ") ? familyParts[10] : " ";
                                string mdChildCode = (familyParts[11] != null && familyParts[11] != " ") ? familyParts[11] : " ";
                                string mdParentCode = (familyParts[12] != null && familyParts[12] != " ") ? familyParts[12] : " ";

                                

                                string fmRecord = (mdSurname +
                                            mdGivenName +
                                            mdBirthDate +
                                            mdBirthPlace +
                                            mdMarriageDate +
                                            mdDeathDate +
                                            mdDeathPlace +
                                            mdSex +
                                            mdChildCode +
                                            mdParentCode);

                               return;


                            }
                            Array.Clear(familyParts, 0, familyParts.Length);
                        }
                    }
                }

Is this any better? Doing it this way I'm getting an "Index array out of range" error.
 
That likely means that Split() is returning an array that has less than 13 elements. (You'll want to recall that arrays in C# are zero based.)
 
Is this any better? Doing it this way I'm getting an "Index array out of range" error.
Brutal honesty? CSV is such an invented wheel you don't need to attack it yourself, in this awkward error prone way

If the file has headers it's about as easy as it gets; two lines of code will import the file to a list of objects ready to be queried
 
This code doesn't make sense:

C#:
string mdDeathPlace = (familyParts[9] != null && familyParts[9] != " ") ? familyParts[9] : " ";
Given that Split never produces null strings in the array, the null check can be removed leaving only "if blah is not a space then blah else a space" - so just string blah = familyParts[x] then

If you want to parse your file using split, so long as no field will ever contain a comma (like a death place of "Austin, Texas") you can have a class:

C#:
public class Person{
    private string[] _s
    public string Surname => _s[2];
    public string GivenName => _s[3];
    ... //put the rest here to this pattern

    public Person(string csvLine){
      _s = csvLine.Split(',');
    }
}


And you turn the file into an array of people with:

C#:
  var people = File.ReadAllLines("path here").Select(line => new Person(line));

But in this modern world, realistically, you'd use a CSV library, because it handles all those edge cases of badly formatted files and columns having different data types for you automatically. I tend to use Sylvan to read my CSV and on a file that looks like:

C#:
ID,GivenName,Surname,BirthDate,...
1,Yu,Nix,1970-01-01,...

The code would be like:
C#:
//declare a class to hold data
public record Person(int ID,GivenName,Surname,BirthDate,...)

//read file
var people = CsvDataReader.Create("demo.csv").GetRecords<Person>().ToArray();
 
Last edited:
Other bits in the code I don't understand:

C#:
if (familyParts[1] == familyRecord)

This test can never be true; familyparts was generated by splitting family record on comma. There is no way to have a string that will split to form two strings such that the second string is equal to the whole string

C#:
string fmRecord = (mdSurname +
                                            mdGivenName + ...

This line smushes all that carefully split data back into one long string with no good way to separate it again.. why?

Finally, the method doesn't actually do anything useful; it produces no output and sets no class level variable, it just reads a file, splits a line then clears the array it generated, until the file has been read.
 
CJARD, I'm so glad to get all this help. But let me go into more detail about what I'm doing. I'm an old RPG400 programmer and just now learning C#. I understand OOPS but syntax is driving me crazy.
1) the CSV library, are you talking about the beginning of the program with using statements? I have read about CSV library and CSV reader and write but had red underline problems with it so I'm working with what I got. Learn slow is the only way I know.
2)The more I work with C# the more I will learn how to combine statements. That again is the hardest part to change from what I used to do to C#.
3) In the main class I get rid of all the commas with the replace "," " " statement. For my intense and purposes right now I don't need the commas.
4) Every time I use public or private I get a ton of red underlines. Not using either of them seems to work ok in this case.
5) To give a little more detail of what I am doing and working with I'll give you some examples. I'm working with a GEDCOM file. Keep in mind that all the GEDCOM sample records are in one file. The first section of the file looks like this:
Code:
0 @I352311062451@ INDI
1 NAME David /Roberts/
2 GIVN David
2 SURN Roberts
1 SEX M
1 FAMC @F589@
1 FAMS @F66@
1 BIRT
2 DATE 1788
2 PLAC Cookeville, Putnam, Tennessee, USA
1 DEAT
2 DATE 27 Jan 1852
2 PLAC Breckinridge, Kentucky, USA
0 @I352311060194@ INDI
1 NAME Effie "Mamie" /Roberts/
2 GIVN Effie "Mamie"
2 SURN Roberts
1 SEX F
1 FAMC @F590@
1 FAMS @F216@
1 BIRT
2 DATE 10/26/1890
2 PLAC Stevensport, Kentucky, USA
1 DEAT
2 DATE 6/14/1986
2 PLAC Plainfield, Hendricks, Indiana, USA
The 0 index is the start of the individual information and continues until the line just before the next 0 index line.
I created an individual (or as you put it person) file that looks like this. (I just took some examples, the GEDCOM data and the individual data are not alike):
Code:
Index ,Individual ID,Surname,Given Name,Birth Date,Birth Place,Marriage Date,Marriage Place,Death Date,Death Place,Sex,Child Code,Spouse Code
555,I352324090247,Dawson,Oscar F.,7/7/1895,Cloverport Breckinridge Kentucky USA, , ,1/28/1962,Louisville Jefferson Kentucky USA,M, ,F226
556,I352324090760,Dawson,Charlotte Dewesse,4/10/1921,Cloverport Breckinridge Kentucky USA, , ,1/24/1994,Louisville Jefferson Kentucky USA,F,F226,F193
The next section of the GEDCOM file is the family records:
Code:
0 @F1@ FAM
1 HUSB @I352327978001@
1 WIFE @I352414678495@
1 CHIL @I352414680445@
1 CHIL @I352414679905@
1 CHIL @I352414679166@
1 CHIL @I352414680611@
1 CHIL @I352414680757@
1 CHIL @I352414680876@
0 @F2@ FAM
1 HUSB @I352336996536@
1 WIFE @I352337606974@
1 CHIL @I352337607734@
0 @F3@ FAM
1 HUSB @I352313966554@
1 WIFE @I352313884789@
1 CHIL @I352314066929@
1 CHIL @I352313971229@
1 CHIL @I352314066609@
1 CHIL @I352313966618@
1 CHIL @I352314067075@
1 CHIL @I352314066770@
1 CHIL @I352313970083@
1 CHIL @I352313969928@
The same system applies. The 0 is the start of the family until the line before the next 0 line. Not shown here are marriage and divorce records that come after the HUSB, WIFE, CHIL records.
I wish I could give you an example of the family file but it is part of the testing I'm doing and right now I don't have records because of it blowing up on me.

What I'm trying to do is make the family file one big file which includes the individual/person file. I can give you the header to the file to show you what I'm doing:
Code:
Family Code,Family Member Tag,Individual Code,Surname,Given,Birth Date,Birth Place,Marriage/Divorce Date,Marriage/Divorce Place,Marriage/Divorce Code,Marriage/Divorce Date,Marriage/Divorce Place,Death Date,Death Place,Spouse Code
So what I'm trying to do is basically marry up the two files together. to do that I created the method FindIndRecord. I want to pass into the method the individual number from the family file and find the matching individual number in the individual file. That is why I'm doing the test:
C#:
if (familyParts[1] == familyRecord)
I've not been able to debug that far because of the index array problem that I'm having. As I say a little bit at a time is how I'm learning this.
Slowing I'm understanding what you are trying to tell me. Gotta break now and watch the fooball game. thanks.
 
Last edited by a moderator:
Back
Top Bottom