How can I change this code in C # so that Visual Studio recognizes that I am not an idiot?
I have 3 lines that go
int selectedOrgId;
foreach (Organization o in PD.orgs)
if (o.orgname == selectedOrgName)
selectedOrgId = o.orgid;
PD.cats.InsertOnSubmit(new Category {
orgid = selectedOrgId,
catname = newCatName
});
The middle line, the loop, is guaranteed in the context of my program to set the value for selectedOrgId
. However Visual Studio puts in the last line because
Using unassigned local variable 'selectedOrgId'
What is the way to solve this problem except
int selectedOrgId = 69;
foreach (Organization o in PD.orgs)
if (o.orgname == selectedOrgName)
selectedOrgId = o.orgid;
PD.cats.InsertOnSubmit(new Category {
orgid = selectedOrgId,
catname = newCatName
});
????
Even though it works, it seems like an inelegant solution as it includes a magic number. I want to know the correct C # style to solve this question.
EDIT:
After looking at some of the discussions here, I had to point out that the database only has orgid
. My operator foreach
should have been written as
foreach (Organization o in PD.orgs)
{
if (o.orgname == selectedOrgName)
{
selectedOrgId = o.orgid;
break;
}
}
Thanks for showing me some of the best ways to do this!
source to share
It seems like you are iterating through the collection trying to find one matching value based on the organization name. You can use LINQ SingleOrDefault()
to find (at most) one match:
var selectedOrg = PD.orgs.SingleOrDefault(o => o.orgname == selectedOrgName);
Then only called InsertOnSubmit()
if the value found is: (otherwise selected Org will be null)
if (selectedOrg != null)
PD.cats.InsertOnSubmit(new Category { orgid = selectedOrg.orgid, catname = newCatName });
source to share
No .
What happens if the condition is o.orgname == selectedOrgName
not met for any value in PD.orgs
? Then it selectedOrgId
will remain uninitialized.
However, the following code may be more "elegant" according to your approach:
int selectedOrgId = PD.orgs.Single(o => o.orgname == selectedOrgName).orgid;
PD.cats.InsertOnSubmit(new Category { orgid = selectedOrgId, catname = newCatName });
Note that your code will install to the selectedOrgId
latest instance, while mine will assume that there is only one.
source to share
Edit: The OP modified the question to indicate that only one item will be found and no multiple solution is required, here is Option 1a
Option 1a - One Linq Method
This provides a linq one line query that filters out unneeded organizations, grabs one item, and selects a new category object to be used as a parameter for your insert. This method will throw an exception if a single element cannot be located, but that is clearly what should happen depending on your question.
PD.cats.InsertOnSubmit(
PD.orgs.Where(o=>o.orgname==selectedOrgName)
.Single()
.Select(o=>new Category { orgid = o.orgId, catname = newCatName })
);
Option 1b - Iterate the filtered list and get the job done
All other answers here suggest using linq and assume that only one entry will be found. Why not just do everything in a loop and use linq to filter the results?
foreach (Organization o in PD.orgs.Where(o=>o.orgname==selectedOrgName))
{
PD.cats.InsertOnSubmit(new Category { orgid = o.orgId, catname = newCatName });
}
The catch here is no if statements and it handles one or more cases. There is a way to do this on one line and remove the explicit for each and use List.ForEach ( see Comparisons ):
PD.orgs.Where(o=>o.orgname==selectedOrgName).ToList()
.ForEach(o=>PD.cats.InsertOnSubmit(new Category { orgid = o.orgId, catname = newCatName }));
Option 2 - use an exception
This will let you know what your intentions are for the code and let Visual Studio know that you've taken care of it. The idea is to keep the code very close to how it is now:
int selectedOrgId;
foreach (Organization o in PD.orgs)
{
if (o.orgname == selectedOrgName)
selectedOrgId = o.orgid;
}
However, at this point, I would suggest using an exception like:
if(selectedOrgId == 0) throw new InvalidDataException("Selected Org Id cannot be 0");
PD.cats.InsertOnSubmit(new Category { orgid = selectedOrgId, catname = newCatName });
source to share
This is not the only problem. You know you will find 1 or more matches, the compiler doesn't know.
But the problem "or more" is also a problem. The code just isn't clear what you want, what's the reason. You have an implied "last win" strategy.
When you use a solution that meets the requirement more closely, the compiler problem goes away without any hacks.
Without Linq:
// int selectedOrgId;
foreach (Organization o in PD.orgs)
if (o.orgname == selectedOrgName)
{
PD.cats.InsertOnSubmit(new Category {
orgid = o.orgid,
catname = newCatName
});
return; // or break;
}
// shouldn't get here
throw new ...
And with Linq
Organization org = PD.orgs.Single(o => o.orgname == selectedOrgName);
PD.cats.InsertOnSubmit(new Category {
orgid = selectedOrgId,
catname = newCatName
});
The method is Single(Predicate)
fully consistent with your problem. It will throw when the result set has! = 1 element.
source to share
Use linq to select an organization with selectedOrgName
and get orgid
:
PD.cats.InsertOnSubmit(new Category {
orgid = PD.orgs.First(o => o.orgname == selectedOrgName).orgid,
catname = newCatName
});
Assumes it selectedOrgName
will always be in PD.orgs
, and I am making this assumption based on the variable name; however, if this is not always the case, you can do the following:
var selectedOrg = PD.orgs.FirstOrDefault(o => o.orgname == selectedOrgName);
if (selectedOrg != null)
{
PD.cats.InsertOnSubmit(new Category {
orgid = selectedOrg.orgid,
catname = newCatName
});
}
source to share
Below is the exact equivalent of what your code does, but it will throw an exception if you ever don't have an appropriate organization (which, as you say, cannot happen):
PD.cats.InsertOnSubmit(new Category {
orgid = PD.orgs.Last(o => o.orgname == selectedOrgName).orgid,
catname = newCatName
});
source to share