C# Question on a changing a string in a function - c#

Is it possible to change a string from another value? Here is my C# code:
if (QuestionNum == 1 && inputAnswer == RightAnswer || inputAnswer == RightAnswerLower)
{
Program.GotQ1Correct = true;
}
I know that in Lua I could of just changed the Program.GotQ1Correct = true; part to
Program.GotQ[QuestionNum]Correct = true;
However was just wondering if this was possible in C#.
Edit
I'm very sorry if I wasn't clear before, so basically in the above lua code it would change GotQ1Correct to GotQ2Correct and so on and was just wondering if there was a similar, simple way to do this in C# without arrays.

seems like you need
// assuming 10 questions
var results = new bool[10];
var correctAnswers = new string[10];
var studAnswers = new string[10];
for (int i; i < 10 ; i++)
{
if(studAnswer[i].ToLower() == correctAnswers[i].ToLower())
results[i] = true;
}
or slightly cleaner
results[i] = studAnswer[i].ToLower() == correctAnswers[i].ToLower();

For more clarity I might do a dictionary.
public IDictionary<int, bool> CheckAnswers(Dictionary<int, string> exam, Dictionary<int, string> answers)
{
var results = new Dictionary<int, bool>();
for(var index = 0; index < exam.Length; index++)
{
if(String.Compare(exam[index], answers[index], true) == 0)
results.Add(exam[index], true);
results.Add(exam[index], false);
}
return results;
}
var correct = CheckAnswers(..., ...).Where(answer => answer.Value == true).Count();
This solution needs refinement, but it is a nice compliment to PM's answer. One of these should at least point you in the proper direction.
The reason I recommended a dictionary, would be you could pass an answer key and exam result. Allowing you to see which are correct and wrong, then use a tally to get the score relatively easy.

So if understand you want to access a property of an object by replacing the name of access property?
You might want to check this post
accessing-object-property-as-string
Copied from the post
System.Reflection.PropertyInfo prop =typeof(YourType).GetProperty("PropertyName");
object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");

Related

C# Mapping a list to numbered variables

Yes, I'm well aware Not to do this, but I have no choice. I'd agree that it's an XYZ issue, but since I can't update the service I have to use, it's out of my hands. I need some help to save some time, maybe learn something handy in the process.
I'm looking to map a list of models (items in this example) to what is essentially numbered variables of a service I'm posting to, in the example, that's the fields a part of new 'newUser'.
Additionally, there may not be always be X amount items in the list (On the right in the example), and yet I have a finite amount (say 10) of numbered variables from 'newUser' to map to (On the left in the example). So I'll have to perform a bunch of checks to avoid indexing a null value as well.
Current example:
if (items.Count >= 1 && !string.IsNullOrWhiteSpace(items[0].id))
{
newUser.itemId1 = items[0].id;
newUser.itemName1 = items[0].name;
newUser.itemDate1 = items[0].date;
newUser.itemBlah1 = items[0].blah;
}
else
{
// This isn't necessary, but this effectively what will happen
newUser.itemId1 = string.Empty;
newUser.itemName1 = string.Empty;
newUser.itemDate1 = string.Empty;
newUser.itemBlah1 = string.Empty;
}
if (items.Count >= 2 && !string.IsNullOrWhiteSpace(items[1].id))
{
newUser.itemId2 = items[1].id;
newUser.itemName2 = items[1].name;
newUser.itemDate2 = items[1].date;
newUser.itemBlah2 = items[1].blah;
}
// Removed the else to clean it up, but you get the idea.
// And so on, repeated many more times..
I looked into an example using Dictionary, but I'm unsure of how to map that to the model without just manually mapping all the variables.
PS: To all who come across this question, if you're implementing numbered variables in your API, please don't- it's wildly unnecessary and time consuming.
As an alternative to fiddling with the JSON, you could get down and dirty and use Reflection.
Given the following test data:
const int maxItemsToSend = 3;
class ItemToSend {
public string
itemId1, itemName1,
itemId2, itemName2,
itemId3, itemName3;
}
ItemToSend newUser = new();
record Item(string id, string name);
Item[] items = { new("1", "A"), new("2", "B") };
Using the rules you set forth in the question, we can loop through the projected fields as so:
// If `itemid1`,`itemId2`, etc are fields:
var fields = typeof(ItemToSend).GetFields();
// If they're properties, replace GetFields() with
// .GetProperties(BindingFlags.Instance | BindingFlags.Public);
for(var i = 1; i <= maxItemsToSend; i++){
// bounds check
var item = (items.Count() >= i && !string.IsNullOrWhiteSpace(items[i-1].id))
? items[i-1] : null;
// Use Reflection to find and set the fields
fields.FirstOrDefault(f => f.Name.Equals($"itemId{i}"))
?.SetValue(newUser, item?.id ?? string.Empty);
fields.FirstOrDefault(f => f.Name.Equals($"itemName{i}"))
?.SetValue(newUser, item?.name ?? string.Empty);
}
It's not pretty, but it works. Here's a fiddle.

Comparing attributes from a List inside a List

Description
My goal is to compare the language of a menu object from the menuList. Since the menuList has the Languages offered as another list it makes it a bit more complicated. So I tried to create a new class object with the same values so I can use menuList.Languages.Contains(languageObject), however I quickly found out that this doesn't work like that. I tried to make a for loop inside a for loop which didn't work either, but could be a failure from my side.
Obviously I can't write something like: MenuList.Languages.Name.Equals("English").
Because of that I am looking for a solution where I can check if the attribute Name of the Languages-List inside the menuList equals a value of my choice.
The Object
private LanguageBox LangEng = new LanguageBox
{
IsoCode = "eng",
Name = "English"
};
The List
var MenuList = menuDataClient.GetMenuByCity(city)
.Select(nap => new MenuBox()
{
Menu = nap.Menu,
Languages = nap.Languages
.Select(lang => new LanguageBox()
{
IsoCode = lang.IsoCode,
Name = lang.Name
}).ToList()
})
.ToList();
The Loop
for (int i = 0; i < MenuList.Count; i++)
{
if (MenuList[i].Languages.Contains(LangEng))
{
System.Console.WriteLine("Success");
}
}
Maybe linq's Where could do the trick? Sth like:
foreach(var item in MenuList)
{
var x = item.Languages.Where(obj => obj.Name == <desired language>);
if (x.Count() > 0)
{
//Success code
break;
}
}
I have found a solution. This LINQ option works if you want to only keep elements in the list which have English or Russian in their Languages-List.
Solution
.Where(lang => lang.Languages.Any(any => any.Name.Equals("English") || any.Name.Equals("Russian")))

Problems with iteration in json object

Im struggling with a json object.
I create the object (RO) with the following code and that Works fine.
string reply = #"" + client.UploadString(url, "POST", LS_json);
RootObject RO = new RootObject();
RO = JsonConvert.DeserializeObject<RootObject>(reply);
RO now contains all the data I have recieved through the json search.
Now, when iterating through the object the foreach iterate one more than (RO) contains:
cnt_V = 0;
foreach (object obj_attributtertype in RO.hits.hits[0]._source.Biz.Rel[cnt_I].org[cnt_III].mem[cnt_IV].attributter[cnt_V].type)
{
if (Convert.ToString(RO.hits.hits[0]._source.Biz.Rel[cnt_I].mem[cnt_III].xsData[cnt_IV].attributes[cnt_V].type) == "KEY_VALUES")
{
LS_ande = "" + Convert.ToString(RO.hits.hits[0]._source.Biz.Rel[cnt_I].mem[cnt_III].xsData[cnt_IV].attributes[cnt_V].values[0].value);
}
cnt_V++;
}
The thing is that when cnt_V == 4 and "points" to the last entry attributes[cnt_V] then LS_ande is filled as supposed (=="KEY_VALUES").
But then the foreach iterates again (cnt_V == 5), no problem here, but when it is assigned to LS_ande then it dumps (of cource because there is no entry with data for cnt_V == 5).
I dont understand whats wrong. Please be gentle with me and feel free to ask for further information.
Thanks in advance.
While I can't answer this definitively because I don't have the data, this is what I would start with:
//take out the long and lengthy parts to make the rest clearer
//I see there are two things here, intentional?
var something = RO.hits.hits[0]._source.Biz.Rel[cnt_I].org[cnt_III].mem[cnt_IV].attributter;
var somethingElse = RO.hits.hits[0]._source.Biz.Rel[cnt_I].mem[cnt_III].xsData[cnt_IV].attributes;
cnt_V = 0;
//Here, you are iterating over something[cnt_V].type, but also change cnt_V in the body.
//Are you sure this is correct?
foreach (object obj_attributtertype in something[cnt_V].type)
{
if (Convert.ToString(somethingElse[cnt_V].type) == "KEY_VALUES")
{
LS_ande = "" + Convert.ToString(somethingElse[cnt_V].values[0].value);
}
cnt_V++;
}
And looking at it that way, here is my stab in the dark.
Iterate with a for over the Count() of items in something
var something = RO.hits.hits[0]._source.Biz.Rel[cnt_I].org[cnt_III].mem[cnt_IV].attributter;
var somethingElse = RO.hits.hits[0]._source.Biz.Rel[cnt_I].mem[cnt_III].xsData[cnt_IV].attributes;
for (var cnt_V = 0; cnt_V < something.Count(); ++cnt_V)
{
if (Convert.ToString(somethingElse[cnt_V].type) == "KEY_VALUES")
{
LS_ande = "" + Convert.ToString(somethingElse[cnt_V].values[0].value);
}
cnt_V++;
}

Select a control by custom property

I've been trying for a while but I'd like to modify a specific control's value without looping through all controls to check if a textbox's id property matches a correct value.
Currently this is the code I have but I thought perhaps using LINQ it's more efficient;
for (int i = 0; i < protectMaxPlayers; i++)
{
// Update the protect time.
protect.setProtectTime(i, protect.getProtectTime(i) - 1);
// Set the progressbar.
foreach (ProtectProgressBar pb in pnlProtect.Controls.OfType<ProtectProgressBar>())
{
if (pb.Id == i)
pb.Value = protect.getProtectTime(i);
}
}
}
This loops through ALL the progressbars in order to find the right one.
Is this possible to get shorter?
Thanks in advance.
LINQ will iterate over whole collection of ProgressBars as well, so it's not any better than your current solution.
You should consider preparing Dictionary<string, ProtectProgressBar> and using it to find the correct one using it's ID:
var bars = pnlProtect.Controls.OfType<ProtectProgressBar>().ToDictionary(c => c.Id, c => c);
for (int i = 0; i < protectMaxPlayers; i++)
{
// Update the protect time.
protect.setProtectTime(i, protect.getProtectTime(i) - 1);
ProtectProgressBar bar;
if(bars.TryGetValue(i, out bar))
{
bar.Value = protect.getProtectTime(i);
}
}
Dictionary<TKey, TValue> lookup is done in O(1) time, so it should be better then you current solution.
to accomplish this task, you must:
Import Linq namespace above.
import System.Linq;
Then use the code like that:
for (int i = 0; i < protectMaxPlayers; i++)
{
// Update the protect time.
protect.setProtectTime(i, protect.getProtectTime(i) - 1);
// Set the progressbar.
ProtectProgressBar pb = pnlProtect.Controls.OfType<ProtectProgressBar>().ToList().Find(k => k.ID == i.ToString());
// check if it was found
if (pb != null)
{
// your code
}
}
Regards, Wiliam.

Use a numeric value in a linq dynamic query string

I am trying to make a dynamic linq query that will check for values based on a string.
First of all, here's the query:
objQry = from o in m_Db.OBJECTS.Where(whereConditions)
select o;
if(!objQry.Any())
{
return null;
}
The whereConditions variable is a string I build and pass as parameter to find out the values I need. Here's examples of valid string:
OBJ_NAME == \"Sword\" and OBJ_OWNER == \"Stan\"
This will return any item whose name is "Sword" and owner is "Stan;
OBJ_COLOR == \"Blue\" OR OBJ_COLOR == \"Red\"
This will return any item which color is either blue or red.
Up to there, I'm fine, but now I have a problem: I need to check a decimal field. So I've tried this string:
OBJ_NUMBER == 1
But the query returns null even if there are objects which OBJ_NUMBER value is 1. It's a decimal. How can I indicate the query that they need to check for a decimal value?
**** EDIT ****
I have tried to "modify" the value passed so that it looks like this:
"CARD_NUMBER == Convert.ToDecimal(1)"
And now I have a different kind of error telling me this:
LINQ to Entities does not recognize the method 'System.Decimal ToDecimal(Int32)' method, and this method cannot be translated into a store expression.
Any clues anyone? I'm still looking for a way to do this. Thanks!
EDIT 2
You can get an example of how my code is shaped by looking at this question.
Let's come back at this problem. I want to check decimal values. Let's say that OBJ_NUMBER is a decimal field.
Using Dynamic Linq, I tried to read the decimal field. Say that I want to get each object which number is 1.27. The whereConditions field would then be shaped like this:
OBJ_NUMBER == 1.27
But then I would get an Invalid real literal '1.27' error. I don't know why.
So I have tried Gert Arnold's solution and done this instead:
decimal bDecimal = decimal.Parce(valueToParse);
param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = bDecimal };
valuesToUse.Add("CARD_NUMBER == #cardNumber");
listParams.Add(param);
But I ended up having 2 problems:
The first problem is that my whereConditions string is shaped this way:
CARD_NUMBER == #cardNumber
But I get the following error:
No property or field 'cardNumber' exists in type 'CARD'
Leading me to believe that it cannot make the link between the object parameter and the string used to do the query.
As you can see, I have a list of Params. This is because I cannot know for sure how many parameters the user will chose. So each time the user enters a new search field, I have to create a new ObjectParameter and store it in a list. Here's how I try to do the thing after:
ObjectParameter[] arrayParameters = listParams.ToArray();
// Convert the list to an array
And then, when I try to make the query:
cardQry = from c in mDb.CARD.Where(whereConditions, arrayParameters)
select c;
But to no avail.
RESULTS
Based on the answered question below, I have developped something "awful", yet functional.
First of all, I ignore every decimal fields because I could never reach them with dynamic linq. Instead, I do this:
var valuesToParse = keyValuePair.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
// Here I parse the value and, if that's the case, the symbol.
decimal baseValue = decimal.Parse(valuesToParse[0]);
if (valuesToParse.Count() > 1)
{
string baseMethod = valuesToParse[1];
if (baseMethod == ">" || baseMethod == ">=")
{
if (baseMethod == ">=")
{
baseValue--;
}
// The list is actually like this: Dictionary<string, object> list = new Dictionary<string, object>();
list.Add("low", baseValue);
// I kind of activate a tag telling me that the user is looking for a higher value.
cardHigher = true;
}
else
{
if (baseMethod == "<=")
{
baseValue++;
}
list.Add("low", baseValue);
cardLower = true;
}
}
else
{
//lowParam = new ObjectParameter("dec", typeof(decimal)) { Value = baseValue };
list.Add("low", baseValue);
}
cardNumberActivated = true;
At the end, when I get the list of objects, I do this:
if (list.Count > 0)
{
(example)
if (cardNumberActivated)
{
if (cardHigher)
{
q = mDb.CARD.Where("CARD_NUMBER >= #0", list["low"]).ToList();
}
else if (cardLower)
{
q = mDb.CARD.Where("CARD_NUMBER <= #0", list["low"]).ToList();
}
else
{
q = mDb.CARD.Where("CARD_NUMBER == #0", list["low"]).ToList();
}
}
}
// Here we get the orinalData with the basic filters.
listToReturn.AddRange(cardQry);
if (q != null)
{
//listToReturn.AddRange(q);
for (int i = 0; i < listToReturn.Count; i++)
{
var priceList1 = listToReturn[i];
if (!q.Any(_item => _item.CARD_NUMBER == priceList1.CARD_NUMBER))
{
listToReturn.RemoveAt(i);
i--;
}
}
}
And it works. This is not an elegant way to make it work, but I can validate the fields the way I wanted, and for this, I am thankful at last.
You should not build a query string with inline predicate values. Use parameters in stead. Then will also be able to specify the type:
var whereConditions= "it.CARD_NUMBER = #cardNumber";
var param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = 1 };
objQry = from o in m_Db.OBJECTS.Where(whereConditions, param);
Edit
I don't know what doesn't work in your code. Here's just a random piece of working code derived from one of my own projects:
var param1 = new ObjectParameter("dec", typeof(decimal)) { Value = 90000m };
var param2 = new ObjectParameter("int", typeof(int)) { Value = 90000 };
var q = ValueHolders.Where("it.DecimalValue >= #dec OR it.IntegerValue > #int",
param1, param2).ToList();
Note that param1, param2 could also be an array of ObjectParameter.

Categories

Resources