Hi I have had to use interfaces before but ive been told i need to implement icomparable in this instance. see below:
internal class doorItem : IComparable
{
public int CompareTo(doorItem other)
{
// The temperature comparison depends on the comparison of the
// the underlying Double values. Because the CompareTo method is
// strongly typed, it is not necessary to test for the correct
// object type.
return GetNumber(productSize).CompareTo(GetNumber(other.productSize));
}
public string variations { get; set; }
public double pricerange { get; set; }
public string viewDetailsLink { get; set; }
public string height { get; set; }
public string width { get; set; }
public string productSize { get; set; }
public string productImage { get; set; }
public int countItemsOnSale { get; set; }
public string optionFor35Product { get; set; }
private int GetNumber(string str)
{
//this method gets the int out of the string
int length = str.Length;
string output = String.Empty;
int test = 0;
bool err = false;
for (int i = 0; i <= length; i++)
{
try
{
test = Convert.ToInt32(str.Substring(i, 1));
}
catch
{
err = true;
}
if (!err)
output += str.Substring(i, 1);
else
break;
}
return Convert.ToInt32(output);
}
}
above is the class i have created, door sizes are returned like this: 4dr, 5dr, 6dr etc.. then the getnumber method gets the int out of the string.
i have a generic list in of my custom class in the main method like this:
List<doorItem> d = new List<doorItem>();
i cant work out how to order this list by door size.... PLEASE HELP
It's easiest to do this using LINQ. Then you don't even need to implement IComparable.
var sortedList = doorList.OrderBy( d => d.GetNumber(d.productSize ).ToList();
And make GetNumber public inside the doorItem class.
I don't know if performance is important, but that method for getting the number is pretty horrible, exceptions should only be used in exceptional circumstances! Suggest something like this
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (Char.IsNumber(c))
{
sb.append(c);
}
}
return Convert.ToInt32(sb.ToString());
For sorting you can do what stecya has suggested, or you could convert this method to a property and sort directly.
public int Size
{
get
{
return GetNumber(this.productSize);
}
}
...
d.OrderBy(x=>x.Size);
Related
So I'm trying to append values to a list (in Json []), that's empty or has items in it. So I check wether the list in the object has items in it or not, if the item doesn't exist, then it creates a new item, if it exists, it rewrites it's value. Here is the code:
if (e.Key == Key.Enter)
{
// When the user pressed enter, do action
Team selected_team = teams.Where(t => t.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
if (selected_team != null)
{
// when the team number is given, go try and find the data of them
Results team_results = results.Where(r => r.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
int index = (Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1);
// Check if the item in the list exists
if (index < team_results.results[inp_tour_part.SelectedIndex].gtks.Length && team_results.results[inp_tour_part.SelectedIndex].gtks[index] != null)
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = gtk_input.Text; // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = "00:00"; // Give the default value
}
}
else
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks.Append(gtk_input.Text); // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks.Append("00:00"); // Give the default value
}
}
SaveResults(results);
// Move to the next UI element
MoveToNextUIElement(e);
}
else
{
MessageBox.Show("Something went somewhere wrong.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
Now, it works fine to rewrite the items, but when the list is empty (default) or when the item doesn't exist, and it needs to add/append the new value, it doesn't crahs and doesn't throw any error... Also it doesn't add the value to my json, now when I initialize the new object for this, it looks like the following:
team_results = new Results()
{
team_number = selected_team.team_number,
results = new Result[2] { new Result{ }, new Result { } } // Fixed length of array for the results. TODO: Needs fix.
};
And the model looks like this:
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public string[] gtks { get; set; }
}
}
Now I just need a list of strings in my json, but I don't have any clue on how to achieve this...
If you MUST, you can resize an array using Array.Resize() method. Please see documentation here.
int[] array = new int[] { 1, 2, 3 };
Array.Resize(ref array, 5);
array[3] = 4;
array[4] = 5;
But it is strongly advised the use of List<T> instead of arrays. After all List<T> uses arrays behind the scenes so you get all the functionality of an array minus most of the cons.
You can use List instead. Thus you don't need to know the array size when instantiating the list.
Why not alter your models so they implement List instead of array. In the constructor of each model just initialize the empty list (or other action depending on your situation)
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public List<Result> results { get; set; }
public Results() {
results = new List<Result>();
}
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public List<string> gtks { get; set; }
public Result() {
gtks = new List<string>();
}
}
}
Then when you have your models you can add to each list like the following:
Results r = new Results();
r.results.Add(new Result()); // or other `result` object here
Result r = new Result();
r.gtks.Add("My String"); // or other `string` here
I think you can implement a method which would create a new array based on original one. Then, you would be able to override that original array with the resulted one (returned by that new method).
The example code would be the following:
var test = new string[1] { "Test string 1" };
test = AddItemToArray(test, "Test string 2");
private static string[] AddItemToArray(string[] original, string item)
{
var result = new string[original.Length + 1];
for (int i = 0; i < original.Length; i++)
{
result[i] = original[i];
}
result[result.Length - 1] = item;
return result;
}
I have a list of objects of a class, made of a string and an int.
public class PatternInfo
{
private string prpatternname;
private int prpatterntier;
public PatternInfo(string patternname, int patterntier)
{
prpatternname = patternname;
prpatterntier = patterntier;
}
}
This is in a seperate file.
I have a list of such objects:
public List<PatternInfo> patternlist;
Now for each obejct of this class in a list, I want to set values of variables to those two values:
foreach (PatternInfo x in patternlist)
{
string a = patternname;
int b = patterntier;
}
for some reason I get "the name patternname/patterntier does not exist in current context". I have tried playing with some solutions, but can't get it to work, please help :)
To align with OP:
public class PatternInfo
{
public string prpatternname { get; }
public int prpatterntier { get; }
public PatternInfo(string patternname, int patterntier)
{
prpatternname = patternname;
prpatterntier = patterntier;
}
}
As you haven't provided how you declare patternlist, I made up the following:
public static void Main()
{
List<PatternInfo> patternlist = null;
for (int i = 0; i < 10; i++)
patternlist.Add(new PatternInfo(i.ToString(), i));
foreach(PatternInfo x in patternlist)
{
string a = x.prpatternname;
int b = x.prpatterntier;
}
}
This is because the attributes are private and attributes of x. Add this to a PatternInfo:
public string name { get;}
public int tier {get;}
Then, in the loop, you can have the following:
string a = x.name;
int b = x.tier;
I have an list with an object datatype which i'm trying to fill and then read out to a string. The list should hold data for each column in a DataGridView:
[Serializable]
public sealed class ColumnOrderItem
{
public int DisplayIndex { get; set; }
public int Width { get; set; }
public bool Visible { get; set; }
public int ColumnIndex { get; set; }
}
private void test()
{
List<ColumnOrderItem> columnOrder = new List<ColumnOrderItem>();
DataGridViewColumnCollection columns = dsgDataGrid.Columns;
for (int i = 0; i < columns.Count; i++)
{
columnOrder.Add(new ColumnOrderItem
{
ColumnIndex = i,
DisplayIndex = columns[i].DisplayIndex,
Visible = columns[i].Visible,
Width = columns[i].Width
});
}
colData = string.Join(",", columnOrder);
MessageBox.Show(colData);
}
what I'm expecting is the MessageBox should display each item value in sequence like DisplayIndex, Width, Visible, ColumnIndex, DisplayIndex, Width, Visible, ColumnIndex...and so on. The problem is that all i get read back is 0,1,2 which seems to be just the ColumnIndex for the 3 columns under the dsgDataGrid which is a DataGridView. Does anyone have any idea how i might output all the data to a single string?
Thanks.
The best option for you is override the ToString method Hence your class definition will be like the following:
[Serializable]
public sealed class ColumnOrderItem
{
public int DisplayIndex { get; set; }
public int Width { get; set; }
public bool Visible { get; set; }
public int ColumnIndex { get; set; }
public override string ToString()
{
StringBuilder overRideString = new StringBuilder();
overRideString.AppendLine("DisplayIndex" + DisplayIndex.ToString());
overRideString.AppendLine("Width" + Width.ToString());
overRideString.AppendLine("Visible" + Visible.ToString());
overRideString.AppendLine("ColumnIndex" + ColumnIndex.ToString());
return overRideString.ToString();
}
}
How to use:
StringBuilder details = new StringBuilder();
foreach (ColumnOrderItem item in columnOrder)
{
details.AppendLine(item.ToString());
}
details.ToString(); // this will give you the required result
You can define ToString for ColumnOrderItem and use
THX for informing me about the implict calling of ToString by String.join #Neijwiert
Eg:
public string ToString()
{
return string.Format("{0},{1},{2},{3}",
this.ColumnIndex,
this.DisplayIndex,
this.Visible,
this.Width);
}
When you call String.join(spliter,enums:IEnumerable<T>)
It works the same as String.join(spliter,enums.Select(i->i.toString()))
Join(String, IEnumerable) is a convenience method that lets you concatenate each member of an IEnumerable collection without first converting them to strings. The string representation of each object in the IEnumerable collection is derived by calling that object's ToString method.
String.Join Method (String, IEnumerable)-MSDN
you might have to add a ToString override in your ColumnOrderItem Class like :
public override string ToString()
{
return string.Format(
"[DisplayIndex: {0}, Width: {1}, Visible: {2}, ColumnIndex: {3}]\n",
DisplayIndex,
Wi`enter code here`dth,
Visible,
ColumnIndex);
}
then when you do var colData = string.Join(",", columnOrder); this should give you the output you wanted for example
Iam implemented a webservice using c# webapi,but my json response array is empty.
My code
public object Post([FromBody] castdet castdet1)
{
mid = castdet1.mid1;
return Request.CreateResponse(jsonvalues(mid));
}
private object jsonvalues(string mid)
{
DataTable dtalcast = GetAllcast();
foreach (DataRow drow in dtalcast.Rows)
{
string mouvieid = drow["MovieMasterId"].ToString();
string actname = drow["ActorName"].ToString();
string charname = drow["CharacterName"].ToString();
if (mouvieid == mid)
{
temp = 1;
castdet.Add(new myobject(actname, charname));
}
}
return castdet;
}
public class castdet
{
public string mid1 { get; set; }
}
public class myobject
{
string actorname;
string charactername;
public myobject(string v1, string v2)
{
actorname = v1;
charactername = v2;
}
}
My json response string is like this [{},{}],its empty.What went wrong for me?
You need to make the fields of myobject be public. Or better yet make them be public properties:
public class myobject
{
public string actorname { get; set; }
public string charactername { get; set; }
public myobject(string actorname, string charactername)
{
this.actorname = actorname;
this.charactername = charactername;
}
}
(You may have other problems - your code is incomplete and does not compile. Also, you should modify your methods to explicitly return the actual types being returned, not just to return object. This allows for compile-time checking for type errors.)
Im making a new years eve quiz for some friends. The quiz itself is done and working I just thought it would be cool to autocorrect the answers once they are posted.
The question is what's the best way to compare the posted object with an object that has all the right answers, reflection?. There has to be a slick way to do it and avoid having a lot of if's.
public class QuizModel
{
public string Name { get; set; }
public string Quiz1 { get; set; }
public string Quiz2 { get; set; }
public string Quiz3 { get; set; }
etc..
}
You dont have to write me any code. I just want some directions on what the best ( and most important the coolest) way to do it :)
As for your explanation, the implementation of this class should be a list of answers (or a dictionary, or an array, etc):
public class QuizModel
{
public string Name { get; set; }
public List<string> Quizs { get; set; }
}
Then, to check if all the answers are the same:
public bool AreEqual(model1, model2){
for(var i = 0; i < Math.Min(model1.Quizs.Count, model2.Quizs.Count); ++i)
if(model1.Quizs[i] != model2.Quizs[i])
return false;
return true;
}
In a similar way you can get the number of answers that are identical.
You don't need to use reflection to compare values, no :)
If all of the values are encapsulated within a model, then so should be the comparison logic. One simple approach could be to just override .Equals(). Something like this:
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is QuizModel))
return false;
var quiz = obj as QuizModel;
return
quiz.Name.Equals(this.Name) &&
quiz.Quiz1.Equals(this.Quiz1) &&
// etc.
}
Of course, that's the easy part. The real challenge is going to be that string comparison logic. Strings sounds like free text input. So if one of the answers is "Christmas Day" then what do you do with inputs like "Christmas day" or "christmas" or "december 25th" and so on? That's up to your business logic. But the actual logic of "are these two objects equal" is pretty straightforward.
Semantically you might choose not to override .Equals() for this purpose. I could see a good argument against it, claiming that the objects are different but simply contain the same values. (A great real world example of this are identical twins.) So you may choose to implement something else, like IEquatable or just a custom method like .IsEqualTo(QuizModel quiz). But the logic therein would be the same either way.
I'm giving you two solutions to your question. I think you want to give scores to your friends(I would do that). If so, here is a solution that give you the score for the answer, I'm supposing that every quiz has the same value and you have the correct answer for all the quiz. First you could try by reflection compare all the values of the quizes, and return total(assuming your quizes have the same value. Then if you want to be more flexible below I suggest you a possible solution when the quizes may have a different value(score).
1)
public class QuizModel
{
public string Name { get; set; }
public string Quiz1 { get; set; }
public string Quiz2 { get; set; }
public string Quiz3 { get; set; }
}
public class QuizComparer
{
public QuizComparer(QuizModel correctOne, IComparer<string> comparer, int quizValue = 1)
{
this.CorrectOne = correctOne;
this.Comparer = comparer;
this.QuizValue = quizValue;
}
public int Compare(QuizModel toCompareOne)
{
Type type = toCompareOne.GetType();
var propertiesInfo = type.GetProperties();
int result = 0;
foreach (var propertyInfo in propertiesInfo)
{
if (propertyInfo.CanRead)
{
var toCompareOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(toCompareOne).ToString();
var correctOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(this.CorrectOne).ToString();
if (Comparer.Compare(toCompareOnePropertyValue, correctOnePropertyValue) == 0)//equals
{
result += QuizValue;
}
}
}
return result;
}
public QuizModel CorrectOne { get; set; }
public IComparer<string> Comparer { get; set; }
public int QuizValue { get; set; }
}
2) Secondly if you want to give to your quizes individual scores, you could find this very helpful:
public class QuizModel
{
public string Name { get; set; }
[QuizValue(value: 1)]
public string Quiz1 { get; set; }
[QuizValue(value: 2)]
public string Quiz2 { get; set; }
[QuizValue(value: 3)]
public string Quiz3 { get; set; }
}
public class QuizComparer
{
public QuizComparer(QuizModel correctOne, IComparer<string> comparer, int quizValue = 1)
{
this.CorrectOne = correctOne;
this.Comparer = comparer;
this.QuizDefaultValue = quizValue;
}
public int Compare(QuizModel toCompareOne)
{
Type type = toCompareOne.GetType();
var propertiesInfo = type.GetProperties();
int result = 0;
foreach (var propertyInfo in propertiesInfo)
{
if (propertyInfo.CanRead && propertyInfo.Name != "Name")
{
var toCompareOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(toCompareOne).ToString();
var correctOnePropertyValue = type.GetProperty(propertyInfo.Name).GetValue(this.CorrectOne).ToString();
int value = GetQuizValue(propertyInfo);
if (Comparer.Compare(toCompareOnePropertyValue, correctOnePropertyValue) == 0)//equals
{
result += value;
}
}
}
return result;
}
private int GetQuizValue(PropertyInfo propertyInfo)
{
var attributes = propertyInfo.GetCustomAttributes(typeof(QuizValue), false);
int value = this.QuizDefaultValue;
if (attributes != null && attributes.Count() > 0)
{
var quizValueAttribute = attributes[0];
if (quizValueAttribute is QuizValue)
{
var quizValue = quizValueAttribute as QuizValue;
value = quizValue.Value;
}
}
return value;
}
public QuizModel CorrectOne { get; set; }
public IComparer<string> Comparer { get; set; }
public int QuizDefaultValue { get; set; }
}
[System.AttributeUsage(System.AttributeTargets.Property)]
public class QuizValue : System.Attribute
{
public QuizValue(int value = 1)
{
this.Value = value;
}
public int Value
{
get;
set;
}
}
Please try like below, May this will leads you to get what you think
It will always compare the Quiz2 with the Quiz1 value.
public string Quiz1 {get; set;}
[CompareAttribute("Quiz1", ErrorMessage = "Quiz2 is mismatch with Quiz1")]
public string Quiz2 { get; set; }
this will give you wrong answers only:
var quiz = new QuizModel() { Name = "Quiz 1", Quiz1 = "Correct answer", Quiz2 = "Correct answer", Quiz3 = "Correct answer" };
var correctQuiz = new QuizModel() { Name = "Quiz 1", Quiz1 = "Correct answer", Quiz2 = "Wrong answer", Quiz3 = "Wrong answer 2" };
Func<QuizModel, List<string>> getListOfAnswers = (currentquiz) =>
(
from property
in typeof(QuizModel).GetProperties()
select property.Name + " " + property.GetValue(currentquiz)
).ToList();
var answers = getListOfAnswers(quiz);
var correctAnswers = getListOfAnswers(correctQuiz);
var wrongAnswers = correctAnswers.Except(answers);
output:
Quiz2 Wrong answer
Quiz3 Wrong answer 2
This solution is using Reflection, LINQ and Anonymous functions at once so it's very cool :)