This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
When does a dictionary throw an IndexOutOfRangeException on Add or ContainsKey?
This one is funky. I can't get to the bottom of it with ease. Found an exception in the log and dug out some old code. Don't ask me about why this is written this way because I have no idea. The question really is what could be conditions for IndexOutOfRangeException to be thrown when the Item of the dictionary is being set. Here is how the thing looks:
public MyEnum { Undefined = 0, B = 1, C = 2, D = 16, All = B | C | D }
public class MC
{
private int _hashCode;
private int _i;
private MyEnum _e;
public MC(int i, MyEnum e)
{
_i = i;
_e = e;
SetHashCode();
}
private SetHashCode()
{
_hashCode = _i * 31 + (int)e;
}
public override bool Equals(object other)
{
if (!(obj is MC))
{
return false;
}
MC other = (MC)obj;
return ((_i == other._i) && (_e == other._e));
}
public override int GetHashCode()
{
return _hashCode;
}
}
...
var d = new Dictionary<MC, DateTime>();
...
// Create and populate the list of MCs
var mcs = new List<MC>();
...
foreach (MC mc in mcs)
{
...
d[mc] = DateTime.UtcNow; // Pukes here
}
And the exception is:
System.IndexOutOfRangeException, Source: mscorlib Index was outside the bounds of the array. at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
Ideas how to make the line to fail? Don't what to diverge your attention to the wrong direction but I thought there was something fishy with the Equals and GetHashCode but I couldn't prove it so far - no repro using a unit testing framework.
The error you are getting is often caused by multi-threaded, un-locked concurrent access to a dictionary.
See: When does a dictionary throw an IndexOutOfRangeException on Add or ContainsKey?
Related
This question already has answers here:
Default parameter for value must be a compile time constant?
(7 answers)
Closed 5 months ago.
I'm not sure how to go about doing this, after a bit of research I couldn't really find something that fits my needs. The only thing I could find is from another coding language entirely. I think I might be over-complicating things but I'm blanking and can't seem to wrap my head around this problem.
Here's a simplified example of what I'm trying to achieve, say I have a class Item:
public class Item {
public int val { get; set; } = 1;
public void Link(Item i) { ... }
}
And in some other class that manages Items, I have this method:
void LinkPair(int val = GetLowestVal()) {
var pair = GetItems(val);
pair[0].Link(pair[1]);
}
Basically what I want it to do is: if given a value val, find and link a pair of Items with matching values, otherwise just link a pair both with the lowest value in the list. Unfortunately void LinkPair(int val = GetLowestTier()) isn't a valid signature. Also, since val is an int I can't set its default to null, otherwise I would so something like this I presume:
void LinkPair(int val = null) {
val = val ?? GetLowestVal();
...
I'd like to avoid having to create another overloaded method since I might end up with quite a few variations of these. Any help would be appreciated!
You can't assign null to an int. You'll have to use int?
void LinkPair(int? val = null) {
val = val ?? GetLowestVal();
If you know that val will never be 0 you can use this as the default :
void LinkPair(int val = 0) {
val = val!=0? val : GetLowestVal();
0 is the default for numbers so this is equivalent to :
void LinkPair(int val = default) {
val = val!=0 ? val : GetLowestVal();
I have a generic method Compare which receives two input parameters of type T in the signature and compares them for equality. A boolean is returned. The logic is fairly straight forward for 'ordinary' c# .net types.
However, the generic type T can also be a List<U> (e.g. List<int> xList and List<int> yList), which I would like to compare for equality. I do not know the type of U at compile time, but can obtain it dynamically as shown in the example below.
I'm trying to use Enumerable.SequenceEqual<V>(), for list comparison, but this method needs to know the type of at compile time. To circumnavigate this, I've tried to dynamically cast the T to List<U>, but without success. An error is thrown at runtime (indicated in the code snippet).
Is there an elegant way of doing a list comparison as attempted below, where the list internal type is not known at compile time? The closest I could come to an answer is here: How to use local variable as a type? Compiler says "it is a variable but is used like a type", and it seems awfully close to what I need, but I could not leverage this to a successful solution.
public bool Compare(T x, T y)
{
bool isEqual;
if (typeof(T).IsSubClassOfGenericBaseType(typeof(List<>)))
{
Type listElementType =
x.GetType().GetGenericArguments().Single();
Type specificListType = (typeof(List<>).MakeGenericType(listElementType));
dynamic xList = x.GetType().MakeGenericType(specificListType); // <-- Exception is thrown here.
dynamic yList = y.GetType().MakeGenericType(specificListType);
isEqual = Enumerable.SequenceEqual(xList, yList);
}
else
{
isEqual = EqualityComparer<T>.Default.Equals(x, y);
}
return isEqual;
}
The Type extension method IsSubClassOfGenericBaseType are as follows:
internal static bool IsSubClassOfGenericBaseType(
this Type type, Type genericBaseType)
{
if ( type.IsGenericType
&& type.GetGenericTypeDefinition() == genericBaseType)
{
return true;
}
if (type.BaseType != null)
{
return IsSubClassOfGenericBaseType(
type.BaseType, genericBaseType);
}
return false;
}
Would something like this work for you?
public static bool Compare(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;
if (x is null || y is null)
return false;
if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());
return x.Equals(y);
}
Usage:
var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 1, 2, 3 };
var c = new List<int> { 1, 2, 4 };
var d = new List<bool>{ true, false, true };
var e = "string";
var f = new Collection<int> { 1, 2, 3 };
var g = new List<short> { 1, 2, 3 };
Console.WriteLine(Compare(a, b)); // True
Console.WriteLine(Compare(a, c)); // False
Console.WriteLine(Compare(a, d)); // False
Console.WriteLine(Compare(a, e)); // False
Console.WriteLine(Compare(a, f)); // True - might not be what you want,
Console.WriteLine(Compare(a, g)); // False
Console.ReadLine();
Note that because I'm using SequenceEqual() (as per your suggestion) then the List<int> compares true to the equivalent Collection<int>. I think this is probably what you want, since a List<int> is a Collection<int>, but just so you are aware.
Also note that you shouldn't call the method Compare() in your code - it might cause people to confuse it with IComparer.Compare().
Do be aware that this solution is likely to be significantly slower than just doing:
public static bool CompareDynamic<T>(T x, T y)
{
return typeof(T).IsSubClassOfGenericBaseType(typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}
This is due to all the casting (and hence boxing, if the elements are value types). If there are few elements, then it won't matter much but for large collections that could be a problem.
For completeness, here is some benchmark code that compares the performance of casting versus using dynamic for a fairly large int list:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace Demo
{
[SimpleJob(RuntimeMoniker.Net50)]
public class Program
{
List<int> a = Enumerable.Range(1, 100_000).ToList();
List<int> b = Enumerable.Range(1, 100_000).ToList();
static void Main()
{
BenchmarkRunner.Run<Program>();
Console.ReadLine();
}
[Benchmark]
public void ViaCompareCast()
{
CompareCast(a, b);
}
[Benchmark]
public void ViaCompareDynamic()
{
CompareDynamic(a, b);
}
public static bool CompareCast(object? x, object? y)
{
if (ReferenceEquals(x, y))
return true;
if (x is null || y is null)
return false;
if (x is IEnumerable a && y is IEnumerable b)
return a.Cast<object>().SequenceEqual(b.Cast<object>());
return x.Equals(y);
}
public static bool CompareDynamic<T>(T x, T y)
{
return IsSubClassOfGenericBaseType(typeof(T), typeof(List<>))
? Enumerable.SequenceEqual((dynamic)x, (dynamic)y)
: EqualityComparer<T>.Default.Equals(x, y);
}
static bool IsSubClassOfGenericBaseType(Type type, Type genericBaseType)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == genericBaseType)
return true;
if (type.BaseType != null)
return IsSubClassOfGenericBaseType(type.BaseType, genericBaseType);
return false;
}
}
}
The results (for a .net 5.0 release build) are as follows:
| Method | Mean | Error | StdDev | Median |
|------------------ |-----------:|---------:|----------:|-----------:|
| ViaCompareCast | 4,930.6 us | 96.79 us | 191.04 us | 4,832.1 us |
| ViaCompareDynamic | 667.6 us | 12.67 us | 28.07 us | 652.7 us |
As you can see, the version using dynamic is more than 70 times faster for this particular data set. So you pays your money and you makes your choice!
This question already has answers here:
C# : Converting Base Class to Child Class
(12 answers)
Closed 3 years ago.
Basically there're 2 classes.
class Motor {
int a;
int b;
int c;
}
class Title : Motor {
int d;
int e;
}
Now a function is passed with an instance of Motor class.
bool AssignNums(Motor m)
{
Title t = (Title)m; //throws exception
//Do other things with "t"
}
And it's called from,
void AddNums()
{
Motor m = new Motor();
m.a = 23;
m.b = 78;
m.c = 109;
AssignNums(m);
}
The above line where the casting is done, doesn't work. It throws a null pointer exception.
I tried:
bool AssignNums(Motor m)
{
Title t = new Title();
t = (Title)m; // Doesn't work.
//Do other things with "t"
}
The above approach also doesn't work.
Coming from a C++ background, it's kinda difficult to understand how casting works in C#.
In C++ below code will work.
bool AssignNums(Motor* m)
{
Title* t = (Title*)m; //Will work
//Do other things with "t"
}
How can this be done in C#? Without tons of code to implement "reflection" or something like that...
In C#, you can't cast an object to a more specific subclass. Imagine what could happen if it were possible:
class Foo : Motor
{
int z;
}
Foo m = new Foo();
bool AssignNums(Motor m)
{
Title t = (Title)m; // Pretend it doens't throw an exception
//Do other things with "t"
t.d = 42; // Oopps! The actual object is Foo, not Title, so there is no field called d
// InvalidCastException is thrown at the line that attempts the cast
}
You can convert it at runtime if the actual type is compatible with the desired one:
bool AssignNums(Motor m)
{
Title t = m as Title;
if (t != null)
{
// Do stuff with t
}
}
Beginning with C# 7, you can use the shorter form
bool AssignNums(Motor m)
{
if (m is Title t)
{
// Do stuf with t
}
}
If handling multiple subclasses, you can also use switch..when
switch (m)
{
case Title t when m is Title:
// Do something with t
break;
case Foo f when m is Foo:
// Do something with f
break;
}
Note, though, if you're branching based on the subclass present at runtime, it's a sign that you may have a design issue.
Use the other C# casting syntax, and use a recent C# feature (that allows associating a variable to the cast immediately):
bool AssignNums(Motor m)
{
if (m is Title t) {
//Do things with "t"
}
}
If you do it this way, you ignore incoming m instances that are not of type Title. The is cast also never throws (neither does the related as operation).
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I have a String array object in a class, i.e, String[] particulars which I want to initialize during runtime. The same code segment worked for another class object which was not array though. Here nd is an object of class.
int i=0;
foreach (DataRow row1 in dt1.Rows)
{
nd.particulars[i] = row1["floor"].ToString();
nd.quantity[i] = (double)row1["area"];
nd.rate[i] = (double)row1["rate"];
nd.amount[i] = (double)row1["amount"];
i++;
}
The following code is throwing some NullReferenceException. The error says:
Object reference not set to an instance of an object.
The class definition is as:
class NoteDetails
{
public string[] particulars;
public double[] quantity;
public double[] rate;
public double[] amount;
public string[] mparticulars;
public double[] mquantity;
public double[] mrate;
public double[] mamount;
public NoteDetails()
{
particulars = null;
quantity = null;
amount = null;
rate = null;
mparticulars = null;
mquantity = null;
mamount = null;
mrate = null;
}
}
Please tell me what I'm doing wrong?
You have to initialize your string array (and your others arrays too). You can do that on the constructor of the class.
nd.particulars = new string[5]; //or whatever size
*NullReferenceException** seems that one of your object is null ( nd or row1 or dt1 ). If something is null do not forget to instanciate it.
You need to debug your code to check where you have this issue.
Furthermore, you should test if your object are null to avoid this error like this :
if( dt1 != null ){
//do what you want
}
or like this (>= C#6 )
dt1?.Rows
I wish to create the following test in NUnit for the following scenario: we wish to test the a new calculation method being created yields results similar to that of an old system. An acceptable difference (or rather a redefinition of equality) between all values has been defined as
abs(old_val - new_val) < 0.0001
I know that I can loop through every value from the new list and compare to values from the old list and test the above condition.
How would achieve this using Nunit's CollectionAssert.AreEqual method (or some CollectionAssert method)?
The current answers are outdated. Since NUnit 2.5, there is an overload of CollectionAssert.AreEqual that takes a System.Collections.IComparer.
Here is a minimal implementation:
public class Comparer : System.Collections.IComparer
{
private readonly double _epsilon;
public Comparer(double epsilon)
{
_epsilon = epsilon;
}
public int Compare(object x, object y)
{
var a = (double)x;
var b = (double)y;
double delta = System.Math.Abs(a - b);
if (delta < _epsilon)
{
return 0;
}
return a.CompareTo(b);
}
}
[NUnit.Framework.Test]
public void MyTest()
{
var a = ...
var b = ...
NUnit.Framework.CollectionAssert.AreEqual(a, b, new Comparer(0.0001));
}
Well there is method from the NUnit Framework that allows me to do tolerance checks on collections. Refer to the Equal Constraint. One uses the AsCollection and Within extension methods. On that note though I am not 100% sure regarding the implications of this statement made
If you want to treat the arrays being compared as simple collections,
use the AsCollection modifier, which causes the comparison to be made
element by element, without regard for the rank or dimensions of the
array.
[Test]
//[ExpectedException()]
public void CheckLists_FailsAt0()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1 = new[] { -0.0004, 0.43520, 1.3454, 345345.0980 };
Assert.That(result1, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [0]"); // fail on [0]
}
[Test]
//[ExpectedException()]
public void CheckLists_FailAt1()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result1a = new[] { 0.0001000000 , 0.4348245000 , 1.3450234000 , 345345.0975980000 };
Assert.That(result1a, Is.EqualTo(expected).AsCollection.Within(0.0001), "fail at [1]"); // fail on [3]
}
[Test]
public void CheckLists_AllPass_ForNegativeDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result2 = new[] { 0.00009900 , 0.43532350 , 1.34552240 , 345345.09809700 };
Assert.That(result2, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}
[Test]
public void CheckLists_StillPass_ForPositiveDiff_of_1over10001()
{
var expected = new[] { 0.0001, 0.4353245, 1.3455234, 345345.098098 };
var result3 = new[] { 0.00010100 , 0.43532550 , 1.34552440 , 345345.09809900 };
Assert.That(result3, Is.EqualTo(expected).AsCollection.Within(0.0001)); // pass
}
NUnit does not define any delegate object or interface to perform custom checks to lists, and determine that a expected result is valid.
But I think that the best and simplest option is writing a small static method that achieve your checks:
private const float MIN_ACCEPT_VALUE = 0.0001f;
public static void IsAcceptableDifference(IList collection, IList oldCollection)
{
if (collection == null)
throw new Exception("Source collection is null");
if (oldCollection == null)
throw new Exception("Old collection is null");
if (collection.Count != oldCollection.Count)
throw new Exception("Different lenghts");
for (int i = 0; i < collection.Count; i++)
{
float newValue = (float)collection[i];
float oldValue = (float)oldCollection[i];
float difference = Math.Abs(oldValue - newValue);
if (difference < MIN_ACCEPT_VALUE)
{
throw new Exception(
string.Format(
"Found a difference of {0} at index {1}",
difference,
i));
}
}
}
You've asked how to achieve your desired test using a CollectionAssert method without looping through the list. I'm sure this is obvious, but looping is exactly what such a method would do...
The short answer to your exact question is that you can't use CollectionAssert methods to do what you want. However, if what you really want is an easy way to compare lists of floating point numbers and assert their equality, then read on.
The method Assert.AreEqual( double expected, double actual, double tolerance ) releases you from the need to write the individual item assertions yourself. Using LINQ, you could do something like this:
double delta = 0.0001;
IEnumerable<double> expectedValues;
IEnumerable<double> actualValues;
// code code code
foreach (var pair in expectedValues.Zip(actualValues, Tuple.Create))
{
Assert.AreEqual(pair.Item1, pair.Item2, delta, "Collections differ.");
}
If you wanted to get fancier, you could pull this out into a method of its own, catch the AssertionException, massage it and rethrow it for a cleaner interface.
If you don't care about which items differ:
var areEqual = expectedValues
.Zip(actualValues, Tuple.Create)
.Select(tup => Math.Abs(tup.Item1 - tup.Item2) < delta)
.All(b => b);
Assert.IsTrue(areEqual, "Collections differ.");