Compare two Lists element-wise containing reference types

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












I am trying to compare two lists containing reference types (custom classes) element-wise, ignoring order. My question relates to the Equals method as shown below.



using System.Collections.Generic;
using System.Linq;

namespace Luxaudi.ViewModels

/// <summary>
/// Contains information from the Canvas class that is relevant to the user interface.
/// </summary>
internal sealed class CanvasViewModel : ViewModel

/// <summary>
/// The display title of the canvas.
/// </summary>
public readonly string Title;
/// <summary>
/// The timeline view model belonging to the canvas view model.
/// </summary>
public readonly TimelineViewModel TimelineViewModel;
/// <summary>
/// Contains information from the Canvas class that is relevant to the user interface.
/// </summary>
public readonly List<NoteMapViewModel> NoteMapViewModels;
/// <summary>
/// Contains information from the Canvas class that is relevant to the user interface.
/// </summary>
public readonly List<ScaleViewModel> ScaleViewModels;

/// <summary>
///
/// </summary>
/// <param name="title">The display title of the canvas project.</param>
/// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
public CanvasViewModel(string title, TimelineViewModel timelineViewModel)

Title = title;
TimelineViewModel = timelineViewModel;
ScaleViewModels = new List<ScaleViewModel>();
NoteMapViewModels = new List<NoteMapViewModel>();


/// <summary>
///
/// </summary>
/// <param name="title">The display title of the canvas project.</param>
/// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
/// <param name="scaleViewModels">The collection of scale view models belonging to the canvas view model.</param>
/// <param name="noteMapViewModels">The collection of note map view models belonging to the canvas view model.</param>
public CanvasViewModel(string title, TimelineViewModel timelineViewModel, List<ScaleViewModel> scaleViewModels,
List<NoteMapViewModel> noteMapViewModels)

Title = title;
TimelineViewModel = timelineViewModel;
ScaleViewModels = scaleViewModels;
NoteMapViewModels = noteMapViewModels;


/// <summary>
/// Compare two CanvasViewModels for object equality.
/// </summary>
/// <param name="obj">The object to check for equality with.</param>
/// <returns>False if the object is not a CanvasViewModel or the member attributes are not equal.</returns>
public override bool Equals(object obj)

CanvasViewModel canvasViewModel = obj as CanvasViewModel;
if(canvasViewModel != null)

if (canvasViewModel.Title == Title && canvasViewModel.TimelineViewModel == TimelineViewModel &&
canvasViewModel.ScaleViewModels.All(ScaleViewModels.Contains) &&
canvasViewModel.ScaleViewModels.Count == ScaleViewModels.Count &&
canvasViewModel.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
canvasViewModel.NoteMapViewModels.Count == NoteMapViewModels.Count)
return true;


return false;





The CanvasViewModel inherits from the generic ViewModel class:



namespace Luxaudi.ViewModels

/// <summary>
/// The basic template of all view models. Contains information from domain classes that is relevant to the user interface.
/// </summary>
internal abstract class ViewModel

public override abstract bool Equals(object obj);




Any gotchas to look out for here?



EDIT: Full code provided as recommended.







share|improve this question



























    up vote
    3
    down vote

    favorite












    I am trying to compare two lists containing reference types (custom classes) element-wise, ignoring order. My question relates to the Equals method as shown below.



    using System.Collections.Generic;
    using System.Linq;

    namespace Luxaudi.ViewModels

    /// <summary>
    /// Contains information from the Canvas class that is relevant to the user interface.
    /// </summary>
    internal sealed class CanvasViewModel : ViewModel

    /// <summary>
    /// The display title of the canvas.
    /// </summary>
    public readonly string Title;
    /// <summary>
    /// The timeline view model belonging to the canvas view model.
    /// </summary>
    public readonly TimelineViewModel TimelineViewModel;
    /// <summary>
    /// Contains information from the Canvas class that is relevant to the user interface.
    /// </summary>
    public readonly List<NoteMapViewModel> NoteMapViewModels;
    /// <summary>
    /// Contains information from the Canvas class that is relevant to the user interface.
    /// </summary>
    public readonly List<ScaleViewModel> ScaleViewModels;

    /// <summary>
    ///
    /// </summary>
    /// <param name="title">The display title of the canvas project.</param>
    /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
    public CanvasViewModel(string title, TimelineViewModel timelineViewModel)

    Title = title;
    TimelineViewModel = timelineViewModel;
    ScaleViewModels = new List<ScaleViewModel>();
    NoteMapViewModels = new List<NoteMapViewModel>();


    /// <summary>
    ///
    /// </summary>
    /// <param name="title">The display title of the canvas project.</param>
    /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
    /// <param name="scaleViewModels">The collection of scale view models belonging to the canvas view model.</param>
    /// <param name="noteMapViewModels">The collection of note map view models belonging to the canvas view model.</param>
    public CanvasViewModel(string title, TimelineViewModel timelineViewModel, List<ScaleViewModel> scaleViewModels,
    List<NoteMapViewModel> noteMapViewModels)

    Title = title;
    TimelineViewModel = timelineViewModel;
    ScaleViewModels = scaleViewModels;
    NoteMapViewModels = noteMapViewModels;


    /// <summary>
    /// Compare two CanvasViewModels for object equality.
    /// </summary>
    /// <param name="obj">The object to check for equality with.</param>
    /// <returns>False if the object is not a CanvasViewModel or the member attributes are not equal.</returns>
    public override bool Equals(object obj)

    CanvasViewModel canvasViewModel = obj as CanvasViewModel;
    if(canvasViewModel != null)

    if (canvasViewModel.Title == Title && canvasViewModel.TimelineViewModel == TimelineViewModel &&
    canvasViewModel.ScaleViewModels.All(ScaleViewModels.Contains) &&
    canvasViewModel.ScaleViewModels.Count == ScaleViewModels.Count &&
    canvasViewModel.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
    canvasViewModel.NoteMapViewModels.Count == NoteMapViewModels.Count)
    return true;


    return false;





    The CanvasViewModel inherits from the generic ViewModel class:



    namespace Luxaudi.ViewModels

    /// <summary>
    /// The basic template of all view models. Contains information from domain classes that is relevant to the user interface.
    /// </summary>
    internal abstract class ViewModel

    public override abstract bool Equals(object obj);




    Any gotchas to look out for here?



    EDIT: Full code provided as recommended.







    share|improve this question























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      I am trying to compare two lists containing reference types (custom classes) element-wise, ignoring order. My question relates to the Equals method as shown below.



      using System.Collections.Generic;
      using System.Linq;

      namespace Luxaudi.ViewModels

      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      internal sealed class CanvasViewModel : ViewModel

      /// <summary>
      /// The display title of the canvas.
      /// </summary>
      public readonly string Title;
      /// <summary>
      /// The timeline view model belonging to the canvas view model.
      /// </summary>
      public readonly TimelineViewModel TimelineViewModel;
      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      public readonly List<NoteMapViewModel> NoteMapViewModels;
      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      public readonly List<ScaleViewModel> ScaleViewModels;

      /// <summary>
      ///
      /// </summary>
      /// <param name="title">The display title of the canvas project.</param>
      /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
      public CanvasViewModel(string title, TimelineViewModel timelineViewModel)

      Title = title;
      TimelineViewModel = timelineViewModel;
      ScaleViewModels = new List<ScaleViewModel>();
      NoteMapViewModels = new List<NoteMapViewModel>();


      /// <summary>
      ///
      /// </summary>
      /// <param name="title">The display title of the canvas project.</param>
      /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
      /// <param name="scaleViewModels">The collection of scale view models belonging to the canvas view model.</param>
      /// <param name="noteMapViewModels">The collection of note map view models belonging to the canvas view model.</param>
      public CanvasViewModel(string title, TimelineViewModel timelineViewModel, List<ScaleViewModel> scaleViewModels,
      List<NoteMapViewModel> noteMapViewModels)

      Title = title;
      TimelineViewModel = timelineViewModel;
      ScaleViewModels = scaleViewModels;
      NoteMapViewModels = noteMapViewModels;


      /// <summary>
      /// Compare two CanvasViewModels for object equality.
      /// </summary>
      /// <param name="obj">The object to check for equality with.</param>
      /// <returns>False if the object is not a CanvasViewModel or the member attributes are not equal.</returns>
      public override bool Equals(object obj)

      CanvasViewModel canvasViewModel = obj as CanvasViewModel;
      if(canvasViewModel != null)

      if (canvasViewModel.Title == Title && canvasViewModel.TimelineViewModel == TimelineViewModel &&
      canvasViewModel.ScaleViewModels.All(ScaleViewModels.Contains) &&
      canvasViewModel.ScaleViewModels.Count == ScaleViewModels.Count &&
      canvasViewModel.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
      canvasViewModel.NoteMapViewModels.Count == NoteMapViewModels.Count)
      return true;


      return false;





      The CanvasViewModel inherits from the generic ViewModel class:



      namespace Luxaudi.ViewModels

      /// <summary>
      /// The basic template of all view models. Contains information from domain classes that is relevant to the user interface.
      /// </summary>
      internal abstract class ViewModel

      public override abstract bool Equals(object obj);




      Any gotchas to look out for here?



      EDIT: Full code provided as recommended.







      share|improve this question













      I am trying to compare two lists containing reference types (custom classes) element-wise, ignoring order. My question relates to the Equals method as shown below.



      using System.Collections.Generic;
      using System.Linq;

      namespace Luxaudi.ViewModels

      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      internal sealed class CanvasViewModel : ViewModel

      /// <summary>
      /// The display title of the canvas.
      /// </summary>
      public readonly string Title;
      /// <summary>
      /// The timeline view model belonging to the canvas view model.
      /// </summary>
      public readonly TimelineViewModel TimelineViewModel;
      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      public readonly List<NoteMapViewModel> NoteMapViewModels;
      /// <summary>
      /// Contains information from the Canvas class that is relevant to the user interface.
      /// </summary>
      public readonly List<ScaleViewModel> ScaleViewModels;

      /// <summary>
      ///
      /// </summary>
      /// <param name="title">The display title of the canvas project.</param>
      /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
      public CanvasViewModel(string title, TimelineViewModel timelineViewModel)

      Title = title;
      TimelineViewModel = timelineViewModel;
      ScaleViewModels = new List<ScaleViewModel>();
      NoteMapViewModels = new List<NoteMapViewModel>();


      /// <summary>
      ///
      /// </summary>
      /// <param name="title">The display title of the canvas project.</param>
      /// <param name="timelineViewModel">The timeline view model which represents the Timeline of the Canvas.</param>
      /// <param name="scaleViewModels">The collection of scale view models belonging to the canvas view model.</param>
      /// <param name="noteMapViewModels">The collection of note map view models belonging to the canvas view model.</param>
      public CanvasViewModel(string title, TimelineViewModel timelineViewModel, List<ScaleViewModel> scaleViewModels,
      List<NoteMapViewModel> noteMapViewModels)

      Title = title;
      TimelineViewModel = timelineViewModel;
      ScaleViewModels = scaleViewModels;
      NoteMapViewModels = noteMapViewModels;


      /// <summary>
      /// Compare two CanvasViewModels for object equality.
      /// </summary>
      /// <param name="obj">The object to check for equality with.</param>
      /// <returns>False if the object is not a CanvasViewModel or the member attributes are not equal.</returns>
      public override bool Equals(object obj)

      CanvasViewModel canvasViewModel = obj as CanvasViewModel;
      if(canvasViewModel != null)

      if (canvasViewModel.Title == Title && canvasViewModel.TimelineViewModel == TimelineViewModel &&
      canvasViewModel.ScaleViewModels.All(ScaleViewModels.Contains) &&
      canvasViewModel.ScaleViewModels.Count == ScaleViewModels.Count &&
      canvasViewModel.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
      canvasViewModel.NoteMapViewModels.Count == NoteMapViewModels.Count)
      return true;


      return false;





      The CanvasViewModel inherits from the generic ViewModel class:



      namespace Luxaudi.ViewModels

      /// <summary>
      /// The basic template of all view models. Contains information from domain classes that is relevant to the user interface.
      /// </summary>
      internal abstract class ViewModel

      public override abstract bool Equals(object obj);




      Any gotchas to look out for here?



      EDIT: Full code provided as recommended.









      share|improve this question












      share|improve this question




      share|improve this question








      edited Jun 14 at 16:51









      Simon Forsberg♦

      48.1k7124283




      48.1k7124283









      asked Jun 5 at 15:10









      Alluring Topaz

      354




      354




















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          3
          down vote













          It looks OK to me, but you could optimize a little bit by comparing the "low-hanging fruits" first:



          public override bool Equals(object obj)

          CanvasViewModel other = obj as CanvasViewModel;

          return ReferenceEquals(this, other) // other == this is "unsafe" if == is implemented by calling Equals().



          Here it is first checked if the argument (reference) equals this. If it does, no further comparison is necessary. Further the scalars ScaleViewModels.Count and NoteMapViewModels.Count are fairly cheap to compare - compared to other.ScaleViewModels.All(...) and if they are different there is no need for further comparison etc...






          share|improve this answer























          • Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
            – Alluring Topaz
            Jun 7 at 19:17







          • 1




            @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
            – Henrik Hansen
            Jun 7 at 19:51











          • The count is probably longer than the two below.
            – paparazzo
            Jun 14 at 15:02










          • Nah, rolledback, I guess I broke something :-]
            – t3chb0t
            Jun 14 at 18:35






          • 1




            @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
            – Henrik Hansen
            Jun 15 at 5:01

















          up vote
          2
          down vote














          public readonly string Title;



          You shouldn't be using public fields. That's what we have properties for. You can make them readonly too by specifying just the get method like that:



          public string Title get; 



          I find it's much easier and less error-prone to implement the equality via the IEquatable<T> interface. This gives you a strongly typed Equals method that you can use to redirect from the default one.



          The signagure of you class would become



          internal sealed class CanvasViewModel : ViewModel, IEquatable<CanvasViewModel>


          and the respective implementations will be



          public override bool Equals(object obj)

          return obj is CanvasViewModel model && Equals(model);



          You can save a few characters by using the new is operator that will try to cast the obj to the specified type and assign the result to the variable if it succeeds. Then it calls the second Equals method.



          public bool Equals(CanvasViewModel other)

          if (ReferenceEquals(other, null)) return false;
          if (ReferenceEquals(other, this)) return true;

          return
          other.Title == Title &&
          other.TimelineViewModel == TimelineViewModel &&
          other.ScaleViewModels.All(ScaleViewModels.Contains) &&
          other.ScaleViewModels.Count == ScaleViewModels.Count &&
          other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
          other.NoteMapViewModels.Count == NoteMapViewModels.Count);

          }


          The first two conditions here are pretty generic and you use them for pretty every implementation of Equals. It doesn't make sense to try to chain them with the actual comparison. Leave them alone and focus on the other properties that are now also much easier to handle when you don't have to care about even more () or tricky || and && combinations.





          internal abstract class ViewModel

          public override abstract bool Equals(object obj);




          We don't use abstract classes like this one because it has no default implementation for anything. It could, should be an interface. It's also not necessary to even define it because the Equals method can be overriden without it. It's already virtual because every object inherits it by default.



          It would make much more sense if you defined it this way



          internal interface IViewModel<T> : IEquatable<T>





          and the respective class



          internal sealed class CanvasViewModel : IViewModel<CanvasViewModel>

          ...



          Some people argue that you shouldn't be using marker-interfaces, but I find they are very usefull and I do it all the time for various reasons.






          share|improve this answer























          • I definitely will be updating the appropriate classes to match your advice.
            – Alluring Topaz
            Jun 15 at 14:48







          • 1




            @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
            – t3chb0t
            Jun 15 at 14:51







          • 1




            Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
            – Alluring Topaz
            Jun 15 at 14:54

















          up vote
          1
          down vote













          As per Henrik Hansen's comment under the original post:




          @AlluringTopaz: I think, the right way is to make a new answer, if you want to add to the original.




          and based on the recommendation to use a strongly typed Equals method in t3chb0t's answer, I should clarify that since no explicit == operator was provided for TimelineViewModel then, the implementation of IEquatable.Equals in CanvasViewModel should be:



          public bool Equals(CanvasViewModel other)

          if (ReferenceEquals(other, null)) return false;
          if (ReferenceEquals(other, this)) return true;

          return
          other.Title == Title &&
          other.TimelineViewModel.Equals(TimelineViewModel) &&
          other.ScaleViewModels.All(ScaleViewModels.Contains) &&
          other.ScaleViewModels.Count == ScaleViewModels.Count &&
          other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
          other.NoteMapViewModels.Count == NoteMapViewModels.Count);






          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195894%2fcompare-two-lists-element-wise-containing-reference-types%23new-answer', 'question_page');

            );

            Post as a guest






























            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            3
            down vote













            It looks OK to me, but you could optimize a little bit by comparing the "low-hanging fruits" first:



            public override bool Equals(object obj)

            CanvasViewModel other = obj as CanvasViewModel;

            return ReferenceEquals(this, other) // other == this is "unsafe" if == is implemented by calling Equals().



            Here it is first checked if the argument (reference) equals this. If it does, no further comparison is necessary. Further the scalars ScaleViewModels.Count and NoteMapViewModels.Count are fairly cheap to compare - compared to other.ScaleViewModels.All(...) and if they are different there is no need for further comparison etc...






            share|improve this answer























            • Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
              – Alluring Topaz
              Jun 7 at 19:17







            • 1




              @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
              – Henrik Hansen
              Jun 7 at 19:51











            • The count is probably longer than the two below.
              – paparazzo
              Jun 14 at 15:02










            • Nah, rolledback, I guess I broke something :-]
              – t3chb0t
              Jun 14 at 18:35






            • 1




              @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
              – Henrik Hansen
              Jun 15 at 5:01














            up vote
            3
            down vote













            It looks OK to me, but you could optimize a little bit by comparing the "low-hanging fruits" first:



            public override bool Equals(object obj)

            CanvasViewModel other = obj as CanvasViewModel;

            return ReferenceEquals(this, other) // other == this is "unsafe" if == is implemented by calling Equals().



            Here it is first checked if the argument (reference) equals this. If it does, no further comparison is necessary. Further the scalars ScaleViewModels.Count and NoteMapViewModels.Count are fairly cheap to compare - compared to other.ScaleViewModels.All(...) and if they are different there is no need for further comparison etc...






            share|improve this answer























            • Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
              – Alluring Topaz
              Jun 7 at 19:17







            • 1




              @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
              – Henrik Hansen
              Jun 7 at 19:51











            • The count is probably longer than the two below.
              – paparazzo
              Jun 14 at 15:02










            • Nah, rolledback, I guess I broke something :-]
              – t3chb0t
              Jun 14 at 18:35






            • 1




              @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
              – Henrik Hansen
              Jun 15 at 5:01












            up vote
            3
            down vote










            up vote
            3
            down vote









            It looks OK to me, but you could optimize a little bit by comparing the "low-hanging fruits" first:



            public override bool Equals(object obj)

            CanvasViewModel other = obj as CanvasViewModel;

            return ReferenceEquals(this, other) // other == this is "unsafe" if == is implemented by calling Equals().



            Here it is first checked if the argument (reference) equals this. If it does, no further comparison is necessary. Further the scalars ScaleViewModels.Count and NoteMapViewModels.Count are fairly cheap to compare - compared to other.ScaleViewModels.All(...) and if they are different there is no need for further comparison etc...






            share|improve this answer















            It looks OK to me, but you could optimize a little bit by comparing the "low-hanging fruits" first:



            public override bool Equals(object obj)

            CanvasViewModel other = obj as CanvasViewModel;

            return ReferenceEquals(this, other) // other == this is "unsafe" if == is implemented by calling Equals().



            Here it is first checked if the argument (reference) equals this. If it does, no further comparison is necessary. Further the scalars ScaleViewModels.Count and NoteMapViewModels.Count are fairly cheap to compare - compared to other.ScaleViewModels.All(...) and if they are different there is no need for further comparison etc...







            share|improve this answer















            share|improve this answer



            share|improve this answer








            edited Jun 15 at 5:29


























            answered Jun 7 at 6:59









            Henrik Hansen

            3,7981417




            3,7981417











            • Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
              – Alluring Topaz
              Jun 7 at 19:17







            • 1




              @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
              – Henrik Hansen
              Jun 7 at 19:51











            • The count is probably longer than the two below.
              – paparazzo
              Jun 14 at 15:02










            • Nah, rolledback, I guess I broke something :-]
              – t3chb0t
              Jun 14 at 18:35






            • 1




              @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
              – Henrik Hansen
              Jun 15 at 5:01
















            • Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
              – Alluring Topaz
              Jun 7 at 19:17







            • 1




              @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
              – Henrik Hansen
              Jun 7 at 19:51











            • The count is probably longer than the two below.
              – paparazzo
              Jun 14 at 15:02










            • Nah, rolledback, I guess I broke something :-]
              – t3chb0t
              Jun 14 at 18:35






            • 1




              @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
              – Henrik Hansen
              Jun 15 at 5:01















            Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
            – Alluring Topaz
            Jun 7 at 19:17





            Would adding parentheses to the && conditions make a difference in the ordering of the boolean evaluation? Is adding them even necessary?
            – Alluring Topaz
            Jun 7 at 19:17





            1




            1




            @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
            – Henrik Hansen
            Jun 7 at 19:51





            @AlluringTopaz: No, parentheses are only useful if you want to break the precedence between && and ||. Take a look at the documentation for these operators in C#
            – Henrik Hansen
            Jun 7 at 19:51













            The count is probably longer than the two below.
            – paparazzo
            Jun 14 at 15:02




            The count is probably longer than the two below.
            – paparazzo
            Jun 14 at 15:02












            Nah, rolledback, I guess I broke something :-]
            – t3chb0t
            Jun 14 at 18:35




            Nah, rolledback, I guess I broke something :-]
            – t3chb0t
            Jun 14 at 18:35




            1




            1




            @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
            – Henrik Hansen
            Jun 15 at 5:01




            @paparazzo: Well, we don't know about TimelineViewModel, but take a look at the source code for List<T>.Count and string.==.
            – Henrik Hansen
            Jun 15 at 5:01












            up vote
            2
            down vote














            public readonly string Title;



            You shouldn't be using public fields. That's what we have properties for. You can make them readonly too by specifying just the get method like that:



            public string Title get; 



            I find it's much easier and less error-prone to implement the equality via the IEquatable<T> interface. This gives you a strongly typed Equals method that you can use to redirect from the default one.



            The signagure of you class would become



            internal sealed class CanvasViewModel : ViewModel, IEquatable<CanvasViewModel>


            and the respective implementations will be



            public override bool Equals(object obj)

            return obj is CanvasViewModel model && Equals(model);



            You can save a few characters by using the new is operator that will try to cast the obj to the specified type and assign the result to the variable if it succeeds. Then it calls the second Equals method.



            public bool Equals(CanvasViewModel other)

            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(other, this)) return true;

            return
            other.Title == Title &&
            other.TimelineViewModel == TimelineViewModel &&
            other.ScaleViewModels.All(ScaleViewModels.Contains) &&
            other.ScaleViewModels.Count == ScaleViewModels.Count &&
            other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
            other.NoteMapViewModels.Count == NoteMapViewModels.Count);

            }


            The first two conditions here are pretty generic and you use them for pretty every implementation of Equals. It doesn't make sense to try to chain them with the actual comparison. Leave them alone and focus on the other properties that are now also much easier to handle when you don't have to care about even more () or tricky || and && combinations.





            internal abstract class ViewModel

            public override abstract bool Equals(object obj);




            We don't use abstract classes like this one because it has no default implementation for anything. It could, should be an interface. It's also not necessary to even define it because the Equals method can be overriden without it. It's already virtual because every object inherits it by default.



            It would make much more sense if you defined it this way



            internal interface IViewModel<T> : IEquatable<T>





            and the respective class



            internal sealed class CanvasViewModel : IViewModel<CanvasViewModel>

            ...



            Some people argue that you shouldn't be using marker-interfaces, but I find they are very usefull and I do it all the time for various reasons.






            share|improve this answer























            • I definitely will be updating the appropriate classes to match your advice.
              – Alluring Topaz
              Jun 15 at 14:48







            • 1




              @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
              – t3chb0t
              Jun 15 at 14:51







            • 1




              Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
              – Alluring Topaz
              Jun 15 at 14:54














            up vote
            2
            down vote














            public readonly string Title;



            You shouldn't be using public fields. That's what we have properties for. You can make them readonly too by specifying just the get method like that:



            public string Title get; 



            I find it's much easier and less error-prone to implement the equality via the IEquatable<T> interface. This gives you a strongly typed Equals method that you can use to redirect from the default one.



            The signagure of you class would become



            internal sealed class CanvasViewModel : ViewModel, IEquatable<CanvasViewModel>


            and the respective implementations will be



            public override bool Equals(object obj)

            return obj is CanvasViewModel model && Equals(model);



            You can save a few characters by using the new is operator that will try to cast the obj to the specified type and assign the result to the variable if it succeeds. Then it calls the second Equals method.



            public bool Equals(CanvasViewModel other)

            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(other, this)) return true;

            return
            other.Title == Title &&
            other.TimelineViewModel == TimelineViewModel &&
            other.ScaleViewModels.All(ScaleViewModels.Contains) &&
            other.ScaleViewModels.Count == ScaleViewModels.Count &&
            other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
            other.NoteMapViewModels.Count == NoteMapViewModels.Count);

            }


            The first two conditions here are pretty generic and you use them for pretty every implementation of Equals. It doesn't make sense to try to chain them with the actual comparison. Leave them alone and focus on the other properties that are now also much easier to handle when you don't have to care about even more () or tricky || and && combinations.





            internal abstract class ViewModel

            public override abstract bool Equals(object obj);




            We don't use abstract classes like this one because it has no default implementation for anything. It could, should be an interface. It's also not necessary to even define it because the Equals method can be overriden without it. It's already virtual because every object inherits it by default.



            It would make much more sense if you defined it this way



            internal interface IViewModel<T> : IEquatable<T>





            and the respective class



            internal sealed class CanvasViewModel : IViewModel<CanvasViewModel>

            ...



            Some people argue that you shouldn't be using marker-interfaces, but I find they are very usefull and I do it all the time for various reasons.






            share|improve this answer























            • I definitely will be updating the appropriate classes to match your advice.
              – Alluring Topaz
              Jun 15 at 14:48







            • 1




              @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
              – t3chb0t
              Jun 15 at 14:51







            • 1




              Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
              – Alluring Topaz
              Jun 15 at 14:54












            up vote
            2
            down vote










            up vote
            2
            down vote










            public readonly string Title;



            You shouldn't be using public fields. That's what we have properties for. You can make them readonly too by specifying just the get method like that:



            public string Title get; 



            I find it's much easier and less error-prone to implement the equality via the IEquatable<T> interface. This gives you a strongly typed Equals method that you can use to redirect from the default one.



            The signagure of you class would become



            internal sealed class CanvasViewModel : ViewModel, IEquatable<CanvasViewModel>


            and the respective implementations will be



            public override bool Equals(object obj)

            return obj is CanvasViewModel model && Equals(model);



            You can save a few characters by using the new is operator that will try to cast the obj to the specified type and assign the result to the variable if it succeeds. Then it calls the second Equals method.



            public bool Equals(CanvasViewModel other)

            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(other, this)) return true;

            return
            other.Title == Title &&
            other.TimelineViewModel == TimelineViewModel &&
            other.ScaleViewModels.All(ScaleViewModels.Contains) &&
            other.ScaleViewModels.Count == ScaleViewModels.Count &&
            other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
            other.NoteMapViewModels.Count == NoteMapViewModels.Count);

            }


            The first two conditions here are pretty generic and you use them for pretty every implementation of Equals. It doesn't make sense to try to chain them with the actual comparison. Leave them alone and focus on the other properties that are now also much easier to handle when you don't have to care about even more () or tricky || and && combinations.





            internal abstract class ViewModel

            public override abstract bool Equals(object obj);




            We don't use abstract classes like this one because it has no default implementation for anything. It could, should be an interface. It's also not necessary to even define it because the Equals method can be overriden without it. It's already virtual because every object inherits it by default.



            It would make much more sense if you defined it this way



            internal interface IViewModel<T> : IEquatable<T>





            and the respective class



            internal sealed class CanvasViewModel : IViewModel<CanvasViewModel>

            ...



            Some people argue that you shouldn't be using marker-interfaces, but I find they are very usefull and I do it all the time for various reasons.






            share|improve this answer
















            public readonly string Title;



            You shouldn't be using public fields. That's what we have properties for. You can make them readonly too by specifying just the get method like that:



            public string Title get; 



            I find it's much easier and less error-prone to implement the equality via the IEquatable<T> interface. This gives you a strongly typed Equals method that you can use to redirect from the default one.



            The signagure of you class would become



            internal sealed class CanvasViewModel : ViewModel, IEquatable<CanvasViewModel>


            and the respective implementations will be



            public override bool Equals(object obj)

            return obj is CanvasViewModel model && Equals(model);



            You can save a few characters by using the new is operator that will try to cast the obj to the specified type and assign the result to the variable if it succeeds. Then it calls the second Equals method.



            public bool Equals(CanvasViewModel other)

            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(other, this)) return true;

            return
            other.Title == Title &&
            other.TimelineViewModel == TimelineViewModel &&
            other.ScaleViewModels.All(ScaleViewModels.Contains) &&
            other.ScaleViewModels.Count == ScaleViewModels.Count &&
            other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
            other.NoteMapViewModels.Count == NoteMapViewModels.Count);

            }


            The first two conditions here are pretty generic and you use them for pretty every implementation of Equals. It doesn't make sense to try to chain them with the actual comparison. Leave them alone and focus on the other properties that are now also much easier to handle when you don't have to care about even more () or tricky || and && combinations.





            internal abstract class ViewModel

            public override abstract bool Equals(object obj);




            We don't use abstract classes like this one because it has no default implementation for anything. It could, should be an interface. It's also not necessary to even define it because the Equals method can be overriden without it. It's already virtual because every object inherits it by default.



            It would make much more sense if you defined it this way



            internal interface IViewModel<T> : IEquatable<T>





            and the respective class



            internal sealed class CanvasViewModel : IViewModel<CanvasViewModel>

            ...



            Some people argue that you shouldn't be using marker-interfaces, but I find they are very usefull and I do it all the time for various reasons.







            share|improve this answer















            share|improve this answer



            share|improve this answer








            edited Jun 16 at 19:20









            Alluring Topaz

            354




            354











            answered Jun 15 at 13:08









            t3chb0t

            31.9k54195




            31.9k54195











            • I definitely will be updating the appropriate classes to match your advice.
              – Alluring Topaz
              Jun 15 at 14:48







            • 1




              @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
              – t3chb0t
              Jun 15 at 14:51







            • 1




              Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
              – Alluring Topaz
              Jun 15 at 14:54
















            • I definitely will be updating the appropriate classes to match your advice.
              – Alluring Topaz
              Jun 15 at 14:48







            • 1




              @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
              – t3chb0t
              Jun 15 at 14:51







            • 1




              Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
              – Alluring Topaz
              Jun 15 at 14:54















            I definitely will be updating the appropriate classes to match your advice.
            – Alluring Topaz
            Jun 15 at 14:48





            I definitely will be updating the appropriate classes to match your advice.
            – Alluring Topaz
            Jun 15 at 14:48





            1




            1




            @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
            – t3chb0t
            Jun 15 at 14:51





            @AlluringTopaz you can do both... I often do. I start with an interface and when I need a default implementation for something I just add an abstract class inbetween and inherit other classes from it. From the interface point of view nothing has changed and this still remains your contract.
            – t3chb0t
            Jun 15 at 14:51





            1




            1




            Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
            – Alluring Topaz
            Jun 15 at 14:54




            Thanks :) I actually edited my comment thinking it would make sense to do exactly what you just said...then you posted lol. I will keep this in mind as well.
            – Alluring Topaz
            Jun 15 at 14:54










            up vote
            1
            down vote













            As per Henrik Hansen's comment under the original post:




            @AlluringTopaz: I think, the right way is to make a new answer, if you want to add to the original.




            and based on the recommendation to use a strongly typed Equals method in t3chb0t's answer, I should clarify that since no explicit == operator was provided for TimelineViewModel then, the implementation of IEquatable.Equals in CanvasViewModel should be:



            public bool Equals(CanvasViewModel other)

            if (ReferenceEquals(other, null)) return false;
            if (ReferenceEquals(other, this)) return true;

            return
            other.Title == Title &&
            other.TimelineViewModel.Equals(TimelineViewModel) &&
            other.ScaleViewModels.All(ScaleViewModels.Contains) &&
            other.ScaleViewModels.Count == ScaleViewModels.Count &&
            other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
            other.NoteMapViewModels.Count == NoteMapViewModels.Count);






            share|improve this answer

























              up vote
              1
              down vote













              As per Henrik Hansen's comment under the original post:




              @AlluringTopaz: I think, the right way is to make a new answer, if you want to add to the original.




              and based on the recommendation to use a strongly typed Equals method in t3chb0t's answer, I should clarify that since no explicit == operator was provided for TimelineViewModel then, the implementation of IEquatable.Equals in CanvasViewModel should be:



              public bool Equals(CanvasViewModel other)

              if (ReferenceEquals(other, null)) return false;
              if (ReferenceEquals(other, this)) return true;

              return
              other.Title == Title &&
              other.TimelineViewModel.Equals(TimelineViewModel) &&
              other.ScaleViewModels.All(ScaleViewModels.Contains) &&
              other.ScaleViewModels.Count == ScaleViewModels.Count &&
              other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
              other.NoteMapViewModels.Count == NoteMapViewModels.Count);






              share|improve this answer























                up vote
                1
                down vote










                up vote
                1
                down vote









                As per Henrik Hansen's comment under the original post:




                @AlluringTopaz: I think, the right way is to make a new answer, if you want to add to the original.




                and based on the recommendation to use a strongly typed Equals method in t3chb0t's answer, I should clarify that since no explicit == operator was provided for TimelineViewModel then, the implementation of IEquatable.Equals in CanvasViewModel should be:



                public bool Equals(CanvasViewModel other)

                if (ReferenceEquals(other, null)) return false;
                if (ReferenceEquals(other, this)) return true;

                return
                other.Title == Title &&
                other.TimelineViewModel.Equals(TimelineViewModel) &&
                other.ScaleViewModels.All(ScaleViewModels.Contains) &&
                other.ScaleViewModels.Count == ScaleViewModels.Count &&
                other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
                other.NoteMapViewModels.Count == NoteMapViewModels.Count);






                share|improve this answer













                As per Henrik Hansen's comment under the original post:




                @AlluringTopaz: I think, the right way is to make a new answer, if you want to add to the original.




                and based on the recommendation to use a strongly typed Equals method in t3chb0t's answer, I should clarify that since no explicit == operator was provided for TimelineViewModel then, the implementation of IEquatable.Equals in CanvasViewModel should be:



                public bool Equals(CanvasViewModel other)

                if (ReferenceEquals(other, null)) return false;
                if (ReferenceEquals(other, this)) return true;

                return
                other.Title == Title &&
                other.TimelineViewModel.Equals(TimelineViewModel) &&
                other.ScaleViewModels.All(ScaleViewModels.Contains) &&
                other.ScaleViewModels.Count == ScaleViewModels.Count &&
                other.NoteMapViewModels.All(NoteMapViewModels.Contains) &&
                other.NoteMapViewModels.Count == NoteMapViewModels.Count);







                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered Jun 16 at 18:56









                Alluring Topaz

                354




                354






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195894%2fcompare-two-lists-element-wise-containing-reference-types%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation