简体   繁体   English

比较两个对象的最佳方法。 测验

[英]Best way to compare two objects. Quiz

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. 必须有一种巧妙的方法来做到这一点,并避免使用过多的if。

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 :) 我只想了解最佳方法(最重要的是最酷的方法):)

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() . 一种简单的方法是仅重写.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? 因此,如果答案之一是“圣诞节”,那么您如何处理“圣诞节”或“圣诞节”或“ 12月25日”之类的输入呢? 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. 从语义.Equals()您可以选择不重写.Equals() 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) . (在现实世界中,一个很好的例子就是同卵双胞胎。)因此,您可以选择实现其他东西,例如IEquatable或只是一个自定义方法,例如.IsEqualTo(QuizModel quiz) But the logic therein would be the same either way. 但是其中的逻辑将是相同的。

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. 以类似的方式,您可以获得相同的答案数。

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; 1)公共类QuizModel {公共字符串Name {get; set; 组; } public string Quiz1 { get; }公用字符串Quiz1 {get; set; 组; } public string Quiz2 { get; }公共字符串Quiz2 {get; set; 组; } public string Quiz3 { get; }公用字符串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: 2)其次,如果您要给测验个人分数,您会发现这非常有帮助:

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. 它将始终将Quiz2Quiz1值进行比较。

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 Quiz2错误答案

Quiz3 Wrong answer 2 Quiz3错误答案2

This solution is using Reflection, LINQ and Anonymous functions at once so it's very cool :) 该解决方案同时使用了Reflection,LINQ和Anonymous函数,因此非常酷:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM