I've created a class "BankAccount.cs" and am using xunit to test it. I'm testing whether the constructor throws an ArgumentException if it's provided with an empty string as an argument (the argument is the bank account number as a string).
My test fails because no Exception is being thrown - I can't figure out why not.
It appears that the constructor isn't even being called; if I let the constructor throw an Exception (rather than implementing this in the setter of AccountNumber), none is thrown either. Also, if I use Console.WriteLine to debug manually, nothing is written to the console.
Exceptions (Debugging) are set to default settings.
using System;
using System.Collections.Generic;
namespace Banking.Models
{
public class BankAccount : IBankAccount
{
/* NOTE: I've deleted non-relevant fields, properties and methods for brevity */
private string _accountNumber;
public string AccountNumber
{
get { return _accountNumber; }
set
{
if(value == string.Empty)
throw new ArgumentException("Accountnumber must have a value");
_accountNumber = value;
}
}
public BankAccount(string account)
{
AccountNumber = account;
Balance = Decimal.Zero;
_transactions = new List<Transaction>();
}
public override string ToString()
{
return $"{AccountNumber} - {Balance}";
}
public override bool Equals(object obj)
{
BankAccount account = obj as BankAccount;
if (account == null) return false;
return AccountNumber == account.AccountNumber;
}
public override int GetHashCode()
{
return AccountNumber?.GetHashCode() ?? 0;
}
}
}
Tests:
using System;
using Xunit;
using Banking.Models;
namespace Tests.Models
{
public class BankAccountTest : IDisposable
{
// private variables
private BankAccount _account;
private string AccountNumber { get; set; }
// Setup
public BankAccountTest()
{
AccountNumber = "123-4567890-02";
_account = new BankAccount(AccountNumber);
}
[Fact]
public void NewAccount_BalanceZero()
{
Assert.Equal(0, _account.Balance);
}
[Fact]
public void NewAccount_CorrectAccountNumber()
{
Assert.Equal(AccountNumber, _account.AccountNumber);
}
[Fact]
public void NewAccount_EmptyString_Fails()
{
Assert.Throws<ArgumentException>(
() => new BankAccount(string.Empty));
}
// TearDown
public void Dispose()
{
}
}
}
Related
So I have a generic repository like this:
using System.Collections.Generic;
using System.Data.Entity;
using System.Threading.Tasks;
namespace TrackIt.UI.Data.Repositories
{
public class GenericRepository<TEntity, TContext> : IGenericRepository<TEntity>
where TContext: DbContext
where TEntity: class
{
protected readonly TContext Context;
protected GenericRepository(TContext context)
{
this.Context = context;
}
public virtual async Task<TEntity> GetByIdAsync(int id)
{
return await Context.Set<TEntity>().FindAsync(id);
}
public bool HasChanges()
{
return Context.ChangeTracker.HasChanges();
}
}
}
And a FriendRepository that inherits from it, with some of its own methods:
using System.Data.Entity;
using System.Threading.Tasks;
using TrackIt.DataAccess;
using TrackIt.Model;
namespace TrackIt.UI.Data.Repositories
{
public class FriendRepository : GenericRepository<Friend, TrackItDbContext>,
IFriendRepository
{
public FriendRepository(TrackItDbContext context): base(context)
{
}
public override async Task<Friend> GetByIdAsync(int id)
{
return await Context.Friends.Include(f => f.PhoneNumbers).SingleAsync(f => f.Id == id);
}
}
}
where TrackItDbContext is just a class inheriting from DbContext, where it has properties that "maps" to the database's tables.
Then, I have an implementing class like this:
namespace TrackIt.UI.ViewModel
{
public class FriendDetailViewModel : DetailViewModelBase, IFriendDetailViewModel
{
public bool HasChanges
{
get { return _hasChanges; }
set
{
if(_hasChanges != value)
{
_hasChanges = value;
OnPropertyChanged();
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
}
}
private Friend _friend;
public Friend Friend
{
get { return _friend; }
private set
{
_friend = value;
OnPropertyChanged();
}
}
private ICommand _addPhoneNumberCommand;
public ICommand AddPhoneNumberCommand
{
get { return _addPhoneNumberCommand; }
set { _addPhoneNumberCommand = value; }
}
public ObservableCollection<FriendPhoneNumberDecorator> PhoneNumbers { get; }
private IFriendRepository _friendRepository;
private IMessageDialogService _messageDialogServiceProvider;
public FriendDetailViewModel(IFriendRepository friendRepository,
IEventAggregator eventAggregator,
IMessageDialogService messageDialogServiceProvider) : base(eventAggregator)
{
_friendRepository = friendRepository;
_messageDialogServiceProvider = messageDialogServiceProvider;
PhoneNumbers = new ObservableCollection<FriendPhoneNumberDecorator>();
AddPhoneNumberCommand = new DelegateCommand(OnAddPhoneNumberExecute);
DeletePhoneNumberCommand = new DelegateCommand(OnDeletePhoneNumberExecute, OnDeletePhoneNumberCanExecute);
}
private void FriendPhoneNumberWrapper_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Ensures that the HasChanges property of the viewmodel is updated
if (!HasChanges)
{
HasChanges = _friendRepository.HasChanges();
}
// If the change in phone number causes validation errors, disable the save button
if (e.PropertyName == nameof(FriendPhoneNumberDecorator.HasErrors))
{
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
}
private void OnAddPhoneNumberExecute()
{
var newNumber = new FriendPhoneNumber();
newNumber.PropertyChanged += FriendPhoneNumberWrapper_PropertyChanged;
PhoneNumbers.Add(newNumber);
Friend.PhoneNumbers.Add(newNumber);
newNumber.Number = "";
}
#endregion
}
}
When using this class, an instance of IFriendRepository is injected by a DI container and assigned to _friendRepository. The line Friend.Model.PhoneNumbers.Add in the OnAddPhoneNumberExecute method adds a PhoneNumber instance (newNumber) to Friend.PhoneNumber. This addition is tracked by Context in HasChanges method in the GenericRepository method (I checked this by debugging), and thus when the _friendRepository.HasChanges() method in FriendPhoneNumberWrapper_PropertyChanged event handler is triggered by the newNumber.Number = "" line, it returns true.
But, when I test if the HasChanges property of the class is updated when I raise the command AddPhoneNumberCommand using the following test:
namespace TrackIt.UITests.ViewModel
{
public class FriendDetailViewModelTests
{
private FriendDetailViewModel _viewModel;
private Mock<IEventAggregator> _eventAggregatorMock;
private Mock<IMessageDialogService> _messageDialogServiceMock;
private Mock<IFriendRepository> _friendRepositoryMock;
private readonly Friend testFriend = new Friend
{
Id = 2,
FirstName = "asdf",
LastName = "asdfasdf",
Email = "test#test.com",
FavoriteLanguage = new ProgrammingLanguage { Id = 1, Name = "C++"},
PhoneNumbers = new List<FriendPhoneNumber> {
new FriendPhoneNumber(){ id = 1, Number = "0123" },
new FriendPhoneNumber(){ id = 2, Number = "4567" },
}
};
public FriendDetailViewModelTests()
{
// Set up dependencies for FriendDetailViewModel class.
_messageDialogServiceMock = new Mock<IMessageDialogService>();
_eventAggregatorMock = new Mock<IEventAggregator>();
_friendRepositoryMock = new Mock<IFriendRepository>();
// Mock the friendrepository getbyidasync method
_friendRepositoryMock.Setup(dp => dp.GetByIdAsync(testFriend.Id)).ReturnsAsync(testFriend);
// Finally, create the FriendDetailViewModel!
_viewModel = new FriendDetailViewModel(_friendRepositoryMock.Object, _eventAggregatorMock.Object, _messageDialogServiceMock.Object);
}
[Fact]
public void ShouldAddNewPhoneNumberEvent()
{
// ARRANGE
// Assign testFriend to Friend (required so that the created phone number can be assigned to an instance, otherwise we get null reference exception)
PrivateObject _viewModelPrivated = new PrivateObject(_viewModel);
_viewModelPrivated.SetProperty(nameof(Friend), testFriend);
// Create a test empty phone number, to be compared later against the phone number created when user presses "Add"
var emptyPhoneNumber = new FriendPhoneNumber();
emptyPhoneNumber.Number = "";
// ACT
_viewModel.AddPhoneNumberCommand.Execute(null);
// ASSERT
// Check if the created phone number is an empty phone number, the dbContext sees there's a change,
// and that the save button can be pressed
Xunit.Assert.Contains(emptyPhoneNumber, _viewModel.PhoneNumbers,
new ByPropertyComparer<FriendPhoneNumberDecorator>(nameof(emptyPhoneNumber.Number)));
Xunit.Assert.True(_viewModel.HasChanges);
Xunit.Assert.True(_viewModel.SaveCommand.CanExecute(null));
}
}
}
the test fails at Xunit.Assert.True(_viewModel.HasChanges); line, which means the _friendRepository.HasChanges() is not updating automatically (i.e. not tracking) when the Friend.Model.PhoneNumbers.Add is called. I realize that this would be due to me mocking the IFriendRepository, and so it may not actually be tracking any changes. Am I right? Should I also mock HasChanges() of _friendRepositoryMock ? Or is there a better way to do this, maybe an in-memory database? But then it would not be a unit test?
i am doing an app to manage the creation of role-playing sessions, but i am having problems with the section to do rules summaries so the Master doesnt have to be reading the core book every sec, i have the data structures in this way.
User have a list of campaigns, that campaign have a list of scenaries and that scenaries have a list of adventures.
Users -> Lcampaings -> Lscenaries -> Ladventures
Each campaign, scenary or adventure, have resources which contains the list of documents, images, resources etc, and a hashset of summaries.
Campaign/Scenary/Adventure -> Resources -> Ldocuments/LImages/.../HashSet Summaries
ok, so to modify the summaries i have implemented equality and gethashcode
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Windows;
namespace ElEscribaDelDJ.Classes
{
public class Resumenes: INotifyPropertyChanged, IEqualityComparer<Resumenes>
{
private string _nombre;
public string Nombre
{
get { return _nombre; }
set {
_nombre = value;
OnPropertyChanged("Nombre");
}
}
private string _etiquetas;
public string Etiquetas
{
get { return _etiquetas; }
set {
_etiquetas = value;
OnPropertyChanged("Etiquetas");
}
}
private string _descripcion;
public string Descripcion
{
get { return _descripcion; }
set {
_descripcion = value;
OnPropertyChanged("Descripcion");
}
}
private int _pagina;
public int Pagina
{
get { return _pagina; }
set {
if (value <= 0)
_pagina = 1;
else
_pagina = value;
OnPropertyChanged("Pagina");
}
}
private string _manual;
public string Manual
{
get { return _manual; }
set {
_manual = value;
OnPropertyChanged("Manual");
}
}
private string _manualurl;
public string ManualUrl
{
get { return _manualurl; }
set
{
_manualurl = value;
OnPropertyChanged("ManualUrl");
}
}
private string _tipoaventura;
public string TipoAventura
{
get { return _tipoaventura; }
set {
_tipoaventura = value;
OnPropertyChanged("TipoAventura");
}
}
private string _nombretipoaventura;
public string NombreTipoAventura
{
get { return _nombretipoaventura; }
set {
_nombretipoaventura = value;
OnPropertyChanged("NombreTipoAventura");
}
}
private int _indice;
public int Indice
{
get { return _indice; }
set
{
_indice = value;
OnPropertyChanged("Indice");
}
}
private List<int> _indiceslibres;
public List<int> IndicesLibres
{
get { return _indiceslibres; }
set
{
_indiceslibres = value;
OnPropertyChanged("IndicesLibres");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
public bool Equals(Resumenes x, Resumenes y)
{
if (x.Nombre.Equals(y.Nombre) && x.Descripcion.Equals(y.Descripcion))
return true;
else
return false;
}
public int GetHashCode(Resumenes obj)
{
MessageBox.Show("El Hash code es " + obj.Nombre.GetHashCode());
return obj.Nombre.GetHashCode();
}
public Resumenes CopiarValores ()
{
return (Resumenes)this.MemberwiseClone();
}
}
}
(In gethashcode i have the messagebox just to know if was called ofc i know it shouldnt be there)
I am using the name and description of two objects to know if they are equally or not, and for gethashcode the name.
I have done this after read a lot of questions about how it works hashcode and equallity, hashcodeA == hashcodeB means they could be equally so name looks like perfect for that and thats why in equallity i use also description, because if you have same name and same description its mostly the same summary.
Ok, so i show a list of all summaries, the user select one, click edit, in the windows for add or edit i do a not in deep copy of the objects and after that i call for example campaign edit summary, where i delete the old object and add the new one, because i readed that's the best way if you have modified the fields used to make the hashcode.
public void EditarResumen(Resumenes resumenviejo, Resumenes resumennuevo)
{
DatosAplicacion.CampanaSeleccionada.Recursos.Resumenes.Remove(resumenviejo);
DatosAplicacion.CampanaSeleccionada.Recursos.Resumenes.Add(resumennuevo);
RecursosAplicacion.SesionUsuario.ReemplazarCampana();
}
"Datosaplicacion" is a static class which have the campaign, scenary and aventure that the users chose from all of them
using System;
using System.Collections.Generic;
using System.Text;
namespace ElEscribaDelDJ.Classes.Utilidades.Aplicacion
{
public static class DatosAplicacion
{
private static Campana _campana = new Campana();
public static Campana CampanaSeleccionada
{
get { return _campana; }
set { _campana = value; }
}
public static int IndiceCampana;
private static EscenarioCampana _escenarioseleccionado = new EscenarioCampana();
public static EscenarioCampana EscenarioSeleccionado
{
get { return _escenarioseleccionado; }
set { _escenarioseleccionado = value; }
}
public static int IndiceEscenario;
private static Aventura _aventuraseleccionada;
public static Aventura AventuraSeleccionada
{
get { return _aventuraseleccionada; }
set { _aventuraseleccionada = value; }
}
public static int IndiceAventuraSeleccionada;
}
}
resumenviejo (oldsummary) is made with
public Resumenes CopiarValores ()
{
return (Resumenes)this.MemberwiseClone();
}
this should be fine because i dont have any reference object or similar.
But when i debugg the application the remove operation always throw false, and never calls the equality operation neither the gethashcode.
And i don't know what is happening.
I used this article to do the operations https://dotnetcodr.com/2017/01/12/how-to-check-whether-two-hashsets-are-equal-in-c-net-2/#:~:text=Two%20HashSet%20objects%20in%20C#,their%20order%20in%20the%20collection.
I have the full code uploaded to github https://github.com/davidgmd/Proyecto-de-fin-de-grado
You have two methods GetHashCode and Equals
public bool Equals(Resumenes x, Resumenes y)
public int GetHashCode(Resumenes obj)
But they are not overriding the correct methods from the framework so they won't be called. You have to override the following to methods, so that they will be used by the framework
public override bool Equals(object obj) {
if (!(obj is Resumenes)) return false;
var other = obj as Resumenes;
return this.Nombre.Equals(other.Nombre) && this.Descripcion.Equals(other.Descripcion);
}
public override int GetHashCode() {
return this.Nombre.GetHashCode();
}
Note, that this is not really needed. It's just to clarify that this instance is compared with the other object passed in.
EDIT
You can use your overriding of IEqualityComparer<Resumenes> but then you will have to pass it to the constructor of the hashset. But it's quite uncommon for the data object you put into a HashSet to implement IEqualityComparer. Better your Resumenes should implement the IEquatable<T> interface
public class Resumenes: INotifyPropertyChanged, IEquatable<Resumenes> {
public override bool Equals(object obj) { ... }
public bool Equals(Resumenes other) { ... }
public override int GetHashCode() { ... }
}
There are a few things here:
since Nombre is effectively the hash-key, if it changes while the item is in the hash: all bets are off; a simple way to avoid that is to make it read-only
it is very odd to have a leaf type implement IEqualityComparer<T>; I wonder if this is a large part of the problem - especially if you haven't passed a explicit comparer into the hash-set; however, honestly, it would be simpler and preferable to implement IEquatable<T> here:
public class Resumenes : INotifyPropertyChanged, IEquatable<Resumenes>
{
// ...
public override bool Equals(object obj) => obj is Resumenes other && Equals(other);
public bool Equals(Resumenes other)
=> other is not null && other.Nombre == this.Nombre && other.Descripcion == this.Descripcion;
public override int GetHashCode()
=> Nombre.GetHashCode();
}
You can do this with a custom equality comparer, but you'd need to explicitly pass such a comparer into the new HashSet<Resumenes>(comparer) constructor. I would expect this comparer to be a singleton instance of a different type, for example ResumenesComparer.Instance. Using IEquatable<T> is far more obvious and convenient.
We are using HttpSessionStateBase to store messages in a set up similar to this working example:
public class HttpSessionMessageDisplayFetch : IMessageDisplayFetch
{
protected HttpSessionStateBase _session;
private IList<ICoreMessage> messages
{
get
{
if (_session[EchoCoreConstants.MESSAGE_KEY] == null)
_session[EchoCoreConstants.MESSAGE_KEY] = new List<ICoreMessage>();
return _session[EchoCoreConstants.MESSAGE_KEY] as IList<ICoreMessage>;
}
}
public HttpSessionMessageDisplayFetch()
{
if (HttpContext.Current != null)
_session = new HttpSessionStateWrapper(HttpContext.Current.Session);
}
public void AddMessage(ICoreMessage message)
{
if (message != null)
messages.Add(message);
}
public IEnumerable<IResultPresentation> FlushMessagesAsPresentations(IResultFormatter formatter)
{
var mToReturn = messages.Select(m => m.GetPresentation(formatter)).ToList();
messages.Clear();
return mToReturn;
}
}
When we pass in a QualityExplicitlySetMessage (which inherits from ICoreMessage, see below) it is saved correctly to messages.
This is how the object looks after being inserted into the messages list, at the end of AddMessage(ICoreMessage message) above.
But when we come to access it after changing controllers the inherited member's properties are null, which causes a variety of null reference exceptions.
This is how the object now looks after we call FlushMessagesAsPresentations. I've commented out var mToReturn... as this tries to access one of these null ref properties.
I'd like to ask the following:
Why is the HttpSessionStateBase failing to capture these values taken
by the inherited type?
Is this an issue in saving to the HttpSession or in retrieving?
Is this anything to do with, as I suspect, inheritance?
Or is the fact I'm potentially calling a new controller that dependency injects the HttpSessionMessageDisplayFetch causing an issue?
I'm a first-time poster so please let me know if I'm making any kind of faux pas - Super keen to learn! Any input is very welcome.
Some potentially useful code snippets:
QualityExplicitlySetMessage
public class QualityExplicitlySetMessage : QualityChangeMessage
{
public QualityExplicitlySetMessage(IQPossession before, IQPossession after, IQEffect qEffect)
: base(before, after, qEffect)
{
IsSetToExactly = true;
}
}
QualityChangeMessage - Working example
public abstract class QualityChangeMessage : CoreMessage, IQualityChangeMessage
{
protected PossessionChange Change;
public PossessionChange GetPossessionChange()
{
return Change;
}
protected QualityChangeMessage(IQPossession before, IQPossession after, IQEffect qEffect)
{
Change = new PossessionChange(before, after, qEffect);
StoreQualityInfo(qEffect.AssociatedQuality);
}
public override IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetQualityResult(this);
}
#region IQualityChangeMessage implementation
public int LevelBefore
{
get { return Change.Before.Level; }
}
//... And so on with values dependent on the Change property.
}
CoreMessage - Working example
public abstract class CoreMessage : ICoreMessage
{
public string MessageType
{
get { return GetType().ToString(); }
}
public string ImageTooltip
{
get { return _imagetooltip; }
set { _imagetooltip = value; }
}
public string Image
{
get { return _image; }
set { _image = value; }
}
public int? RelevantQualityId { get; set; }
protected void StoreQualityInfo(Quality q)
{
PyramidNumberIncreaseLimit = q.PyramidNumberIncreaseLimit;
RelevantQualityId = q.Id;
RelevantQualityName = q.Name;
ImageTooltip = "<strong>" + q.Name + "</strong><br/>" + q.Description + "<br>" +
q.EnhancementsDescription;
Image = q.Image;
}
public virtual IResultPresentation GetPresentation(IResultFormatter formatter)
{
return formatter.GetResult(this);
}
}
UserController - Working example.
public partial class UserController : Controller
{
private readonly IMessageDisplayFetch _messageDisplayFetch;
public UserController(IMessageDisplayFetch messageDisplayFetch)
{
_messageDisplayFetch = messageDisplayFetch;
}
public virtual ActionResult MessagesForStoryletWindow()
{
var activeChar = _us.CurrentCharacter();
IEnumerable<IResultPresentation> messages;
messages = _messageDisplayFetch.FlushMessagesAsPresentations(_storyFormatter);
var vd = new MessagesViewData(messages)
{
Character = new CharacterViewData(activeChar),
};
return View(Views.Messages, vd);
}
}
I don't know if I'm missing something here but isn't it strange that my code below always raises an exception on List.Contains part although I know for sure that list contain that element:
using System;
using System.Linq;
using System.Collections.Generic;
class SomeClass
{
public string param1 {get; private set;}
public string param2 {get; private set;}
private SomeClass(){}
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if(!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main (string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Quote from the documentation of the Contains method:
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable(Of T).Equals method for T (the type of values in the list).
So you could implement IEquatable<T> on your objects if you want the Contains method to determine if 2 instances of SomeClass are equal:
class SomeClass: IEquatable<SomeClass>
{
public string param1 { get; private set; }
public string param2 { get; private set; }
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public bool Equals(SomeClass other)
{
return param1 == other.param1 && param2 == other.param2;
}
}
Another possibility is to implement a custom EqualityComparer<T>:
class SomeClassEqualityComparer : IEqualityComparer<SomeClass>
{
private static readonly SomeClassEqualityComparer _instance = new SomeClassEqualityComparer();
public bool Equals(SomeClass x, SomeClass y)
{
return x.param1 == y.param1 && x.param2 == y.param2;
}
public int GetHashCode(SomeClass obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + obj.param1.GetHashCode();
hash = hash * 23 + obj.param2.GetHashCode();
return hash;
}
}
public static IEqualityComparer<SomeClass> Instance
{
get { return _instance; }
}
}
and then use the following overload of the Contains method:
if (!myList.Contains(someClass, SomeClassEqualityComparer.Instance))
throw new System.ArgumentException("some error");
You're not removing the same instance of SomeClass. This will work:
public static void Main ()
{
var _someClass = new SomeClass2();
var someClass = new SomeClass("aaa", "bbb");
_someClass.Add(someClass);
try
{
_someClass.Remove(someClass);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
To make your original code work you would need to implement IEquatable. See http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx.
Sorry I didn't spend more time on the hash code implementation. I don't even remember if ^ is the right xor operator... I suppose I could rot13 before the xor, but that seemed kinda silly.
using System;
using System.Collections.Generic;
namespace DoesItCompile
{
class SomeClass
{
private object param1;
private object param2;
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public override bool Equals(object oThat)
{
if (!(oThat is SomeClass))
return false;
SomeClass scThat = (SomeClass)oThat;
if (!string.Equals(this.param1, scThat.param1))
return false;
if (!string.Equals(this.param2, scThat.param2))
return false;
return true;
}
public override int GetHashCode()
{
return this.param1.GetHashCode() ^ this.param2.GetHashCode();
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if (!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main(string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
Console.WriteLine("Have a nice president's day.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
}
}
P.S. - I've no clue why you brought Zelda's stalker into the question, but I'm sure there's a good reason.
I have the following class structure:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
namespace contractsTest
{
class Program
{
static void Main(string[] args)
{
IService s = new Service();
s.sendMessage(MessagesCreator.TestMessage);
}
}
class Service : IService
{
public void DoSomething(Message m)
{
}
}
static class MessageNames
{
public static string TestMessage
{
get
{
Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.Result<string>()));
return "TestMessage";
}
}
}
class Message
{
public Message(string _name)
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
Contract.Ensures(this.Name == _name);
this.Name = _name;
}
public string Name { get; private set; }
}
static class MessagesCreator
{
public static Message TestMessage
{
get
{
Contract.Ensures(Contract.Result<Message>() != null);
Contract.Ensures(Contract.Result<Message>().Name == MessageNames.TestMessage);
return new Message(MessageNames.TestMessage);
}
}
}
static class Extensions
{
public static void sendMessage(this IService service, Message m)
{
Contract.Requires<ArgumentNullException>(service != null);
Contract.Requires<ArgumentNullException>(m != null);
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(m.Name));
service.DoSomething(m);
}
}
[ContractClass(typeof(IServiceContract))]
interface IService
{
void DoSomething(Message m);
}
[ContractClassFor(typeof(IService))]
abstract class IServiceContract : IService
{
public void DoSomething(Message m)
{
Contract.Requires<ArgumentNullException>(m != null);
Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(m.Name));
// Do Something
}
}
}
In Main i get the following Warning CodeContracts: requires unproven: !string.IsNullOrWhiteSpace(m.Name)
Any idea how to fix it?
If I change main to:
static void Main(string[] args)
{
IService s = new Service();
Message messagesCreatorTestMessage = MessagesCreator.TestMessage;
if (string.IsNullOrWhiteSpace(messagesCreatorTestMessage.Name))
throw new InvalidOperationException();
s.sendMessage(messagesCreatorTestMessage);
}
the warning disappears, but there should be other more elegant ways of doing this.
The Ensures in the Message constructor only specifies that the condition will be true when the constructor finishes; it does not indicate that the condition will be true for the life of the Message instance.
To do this, use the Contract.Invariant method:
class Message
{
[ContractInvariantMethod]
private void MessageInvariants()
{
Contract.Invariant(!string.IsNullOrWhiteSpace(Name));
}
public Message(string _name)
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
Contract.Ensures(this.Name == _name);
this.Name = _name;
}
public string Name { get; private set; }
}
It's possible that this is the problem:
// In the Message constructor
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_componentName));
I suspect you mean:
Contract.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(_name));
It's not clear to me where _componentName even comes from...