ToLookup IEqualityComparer arguments always null - c#

I've stumbled into a weird problem, which does not really make sense to me.
I've got a business object Address with a property Location (with the type SqlGeography). For the sake of my requirement i have to do a lookup on the location, because there may be multiple addresses per exact location.
Since SqlGeography is a complex type i suspected that maybe the lookup isn't working because it isn't based on location coordinates for some reason so i did this:
public class Address
{
public Address(byte[] location)
{
Location = SqlGeography.Deserialize(new SqlBytes(location));
}
public SqlGeography Location { get; set; }
}
public class SqlGeographyComparer : IEqualityComparer<SqlGeography>
{
public bool Equals(SqlGeography x, SqlGeography y)
{
// !!! always entered but for some reason x + y always null
if (x == null && y == null)
return true;
if (x == null ^ y == null)
return false;
return x.STEquals(y).IsTrue;
}
public int GetHashCode(SqlGeography obj)
{
return obj.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
var addresses = GetAddresses();
// should be 2 but it's 3 results
var addressesLookup = addresses.ToLookup(d => d.Location);
// should be 2 but it's 3 results
var addressesLookup2 = addresses.ToLookup(d => d.Location, new SqlGeographyComparer());
Console.ReadLine();
}
private static IList<Address> GetAddresses()
{
// 230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,64
var result = new List<Address>();
result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 64 }));
result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 64 }));
result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 63 }));
return result;
}
}
Is this some weird bug i haven't heared about where ToLookup just doesn't pass objects into the given comparer instance?!

Once i changed SqlGeographyComparer to override its method like this:
public int GetHashCode(SqlGeography obj)
{
unchecked
{
return ((obj.Lat.GetHashCode() * 397) ^ obj.Long.GetHashCode());
}
}
it worked correctly.
Turns out GetHashCode has to mimic the required equality comparison (as written in Equals) in order for arguments to work properly.
Reference for implementing GetHashCode in case someone else stumbles upon this question and is wondering about 397:
What is the best algorithm for an overridden System.Object.GetHashCode?

Related

Linq Aggregate function returns 0 instead of correct value

I'm trying to multiply all the values in integer array. The output of the given input array is expected to be a negative value but instead it returned as 0.
int[] nums = new int[] {41,65,14,80,20,10,55,58,24,56,28,86,96,10,3,84,4,41,13,32,42,43,83,78,82,70,15,-41};
Console.WriteLine(ArraySign(nums));
int ArraySign(int[] nums)
{
var value= nums.Aggregate(1, (x, y) => x * y); // returns 0
// var value= nums.Aggregate((x, y) => x * y); // returns 0
Console.WriteLine(value);
return value;
}
The result of multiplying the numbers in your array exceeds the limit of primitive numeric types like int and long. Consider using BigInteger Instead:
using System.Numerics; // Remember to add reference to "System.Numerics".
BigInteger[] nums = new BigInteger[] { 41, 65, 14, 80, 20, 10, 55, 58, 24, 56, 28, 86, 96, 10, 3, 84, 4, 41, 13, 32, 42, 43, 83, 78, 82, 70, 15, -41 };
BigInteger result = nums.Aggregate((x, y) => x * y);
Console.WriteLine(result); // -4198344456762767222202786622577049600000000

How to unescape an UTF-8 escaped byte array to an unescaped byte array without allocating a String

I have a Span<byte> representing an escaped string UTF-8 like:
Binary represention:
byte[20] { 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 92, 117, 50, 48, 97, 99, 32, 33 }
Escaped represention:"Hello world \u20ac !"
Desired binary result:
byte[17] { 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 226, 130, 172, 32, 33 }
I tried to transcode the escaped \u20ac by using the GetString() method:
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString())
But this is not unescaping the input.
Is there any way to achieve to the same result ?
// Not working solution
public void NotWorkingUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
var tmp = Encoding.UTF8.GetString(source);
Encoding.UTF8.GetBytes(tmp, destination);
}
// Unknown solution
// UTF-8 escaped byte array -> UTF8-8 unescaped byte array
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
// ?
}
Are you looking for a method that does all the work?
You could simply use this:
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(source), destination);
}
Or prevent any exception:
public void FastUnescape(ReadOnlySpan<byte> source, Span<byte> destination)
{
if (source.Length <= destination.Length)
{
Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(source), destination);
}
}
Update:
There is another way to do the conversion without using Encoding.UTF8, by seeing the #JonSkeet response you could implement the following:
public static void AnotherMethod(ReadOnlySpan<byte> source, Span<byte> destination)
{
for (int i = 0; i < source.Length; i++)
{
destination[i] = (byte) (Convert.ToChar(source[i]));
}
}
The problem with this code is that when using Convert.toChar, the conversion is done to an equivalent Unicode character no UTF-8 character, which is why & 0x7f is used in the post of the answer to obtain values in the ASCII range.
I did not do many tests in terms of performance or functionality with other special characters that you want to escape, however I have achieved the same results

Serialising an object to JSON, and then using that to send a query in elastic search using NEST

I get a bit confused and frustrated when it comes to using NEST to querying, as it seems very hit and miss. I have no trouble querying when using standard JSON, so I was wondering if there was some way to query using a JSON object, I have code below
var query = "bkala";
var q = new
{
query = new
{
text = new
{
_all = "jane"
}
}
};
var qJson = JsonConvert.SerializeObject(q);
var hits = client.Search<Users>(qJson);
However, I get the error "Cannot convert from type string to System.Func, Nest.ISearchRequest"
If anyone knows how I can simply query using a JSON object, that would be fantastic, cheers in advance.
NEST and Elasticsearch.Net, the low level client that NEST uses under the covers, are flexible in how you wish to query. With NEST you have a couple of different ways:
NEST - High level client
1.Fluent API
var query = "bkala";
var searchResult = client.Search<MyDocument>(s => s
.Query(q => q
.Match(m => m
.Field("_all")
.Query(query)
)
)
);
Laid out as above, this API uses lambda expressions to define a fluent interface that mimics the structure of the Elasticsearch json API and query DSL.
2.Object Initializer Syntax
var query = "bkala";
var request = new SearchRequest<MyDocument>
{
Query = new MatchQuery
{
Field = "_all",
Query = query
}
};
var searchResult = client.Search<MyDocument>(request);
If lambda expressions are not your thing, then you can always define your searches using specific search types.
Elasticsearch.Net - Low level client
In cases where you would like to query with anonymous types (as per your question), json strings or a byte representation of a query, then you can use the low level client, Elasticsearch.Net, to achieve this. The low level client is exposed on the high level client through the .LowLevel property
1.Anonymous types
var query = new
{
query = new
{
match = new
{
_all = new
{
query = "bkala"
}
}
}
};
var searchResult = client.LowLevel.Search<SearchResponse<MyDocument>>(query);
Using the low level client on the high level client means that you can still take advantage of using Json.NET to deserialize search results; in this example, the search response can be accessed through searchResult.Body
2.Json string
var query = #"
{
""query"": {
""match"": {
""_all"": {
""query"": ""bkala""
}
}
}
}";
var searchResult = client.LowLevel.Search<SearchResponse<MyDocument>>(query);
3.Byte array
var bytes = new byte[] { 123, 13, 10, 32, 32, 34, 113, 117, 101, 114, 121, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 34, 109, 97, 116, 99, 104, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 34, 95, 97, 108, 108, 34, 58, 32, 123, 13, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 113, 117, 101, 114, 121, 34, 58, 32, 34, 98, 107, 97, 108, 97, 34, 13, 10, 32, 32, 32, 32, 32, 32, 125, 13, 10, 32, 32, 32, 32, 125, 13, 10, 32, 32, 125, 13, 10, 125 };
var searchResult = client.LowLevel.Search<SearchResponse<MyDocument>>(bytes);
All of the above methods produce the following query
{
"query": {
"match": {
"_all": {
"query": "bkala"
}
}
}
}
Check out the Getting started guide on the github repo as well as the documentation on the Elastic website. We are continually working to improve documentation and PRs are more than welcome for areas where you feel we are lacking :)

Check whether the array contains in array of arrays in LINQ expression

I have some problem with my unit test which work with fake Context(means without database connection). On productive environment it work with connection to sql and everything is clear. But with fake context happened something strange - not find array "item.OfferKey" in the array of arrays "validCartItems"
//Array of arrays validCartItems values for example
byte[] offerKey1 = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
byte[] offerKey2 = { 31, 163, 254, 225, 35, 203, 119, 47, 65, 244, 24, 199, 28, 56, 110, 215 };
byte[][] validCartItems = new byte[4][];
validCartItems[0] = offerKey1;
validCartItems[1] = offerKey1;
validCartItems[2] = offerKey1;
validCartItems[3] = offerKey2;
//Example of ItemPrice in _dataContext.ItemPrices
var itemPriceInFakeContext = new ItemPrice()
{
OfferKey = offerKey1,
//some other properties
};
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
In this case no elements found. But in case we work with database everithing is all right.
To solve the problem, I wrote the following code:
var itemPricesUncheckOfferKey = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
//&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
List<ItemPrice> itemPrices = new List<ItemPrice>();
foreach (var itemPrice in itemPricesUncheckOfferKey)
{
foreach (var validCartItem in validCartItems.Distinct())
{
if (validCartItem.SequenceEqual(itemPrice.OfferKey))
itemPrices.Add(itemPrice);
}
}
But it does not look like a good solution. Could you tell me the solution within LINQ?
UPD
UnitTest code:
[TestMethod]
public void AddCartItems_Test()
{
User user;
InitUser(out user);
List<AddCartItem> addCartItems;
addCartItems = InitAddCartItem();
ICartService cartService;
InitCartService(out cartService);
List<AddCartItemRezult> addCartItemRezults = cartService.AddCartItems(user, addCartItems);
Assert.AreEqual(4, addCartItemRezults.Count);
int countAllGood = 0;
foreach (var addCartItemRezult in addCartItemRezults)
{
if (addCartItemRezult.IsSuccess) countAllGood++;
}
Assert.AreEqual(1, countAllGood);
}
private void InitCartService(out ICartService cartService )
{
DataFakeContext dataFakeContext = new DataFakeContext();
DataContext_InitUsers(ref dataFakeContext);
DataContext_ItemPrices(ref dataFakeContext);
DataContext_CartItems(ref dataFakeContext);
IDeliveryService deliveryService = new DeliveryFakeService(dataFakeContext);
cartService = new CartService(dataFakeContext, deliveryService);
}
private void DataContext_ItemPrices(ref DataFakeContext dataFakeContext)
{
dataFakeContext.ItemPrices = new ItemPriceDbSet();
byte[] OfferKeyPriv = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
var itemPrice1 = new DataAccess.Sql.NavisionModel.ItemPrice()
{
Inventory = 2075,
ItemID = "475931",
LineAmount = (decimal)389.9300,
LineAmountWithMargin = (decimal)522.5062,
Multiplicity = 1,
OfferKey = OfferKeyPriv,
//some other properties
};
dataFakeContext.ItemPrices.Add(itemPrice1);
}
I use Repository.Pattern.Ef6;
In your code you're creating byte[] offerKey1 = ... and saving it into itemPriceInFakeContext. And you should use the same variable to adding this into your _dataContext. I mean exactly the same - not the save value but the reference to the same object.
Like this:
//Array of arrays validCartItems values for example
byte[] offerKey1 = { 30, 163, 252, 225, 36, 208, 128, 47, 64, 244, 34, 199, 28, 57, 110, 215 };
byte[] offerKey2 = { 31, 163, 254, 225, 35, 203, 119, 47, 65, 244, 24, 199, 28, 56, 110, 215 };
byte[][] validCartItems = new byte[4][];
validCartItems[0] = offerKey1;
validCartItems[1] = offerKey1;
validCartItems[2] = offerKey1;
validCartItems[3] = offerKey2;
//Example of ItemPrice in _dataContext.ItemPrices
var itemPriceInFakeContext = new ItemPrice()
{
OfferKey = offerKey1, // use the same object
//some other properties
};
// add fake item price to data context
_dataContext.ItemPrices.Add(itemPriceInFakeContext );
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
That should help.
p.s. you faced this problem because of differences between how runtime compares byte[] and how it does EF and SQL.
In runtime it compares by references. But your LINQ query (on executing) converts this byte[] array (I believe) into the string. And on SQL side it compares the string which will be compared by value.
var itemPrices = _dataContext
.ItemPrices
.Where(item =>
item.UserID == user.UniqueID
&& itemsPartID.Contains(item.PartID)
&& validCartItems.Contains(item.OfferKey)
&& item.CurrencyID == defaultCurrencyCode
&& item.Inventory > 0)
.ToList();
Your LINQ query seems to have no error in it. Please check the dataContext if it is initialized and whether the connection to the database is ok.

How to convert ASCII data to EBCDIC in C#?

I read about conversion of ASCII to EBCDIC using this link;
Convert String from ASCII to EBCDIC in Java?
But this is in java. My requirement is in C#.Net.
So can you please help me with this?
Thanks & Regards,
Krishna Kumar
Here's an implementation (by #Jon Skeet) you might find useful.
I tried the above code, and found it did not work for me.
For example, '04' (0x3034) ascii translated to 0x00f000f4 ebcdic. Problem seemed to be the encoding.
Played with several approches to change this, but finally found the best solution was the most basic. Instead of using Convert.ToChar, I plugged the hex value into the array.
Please see following:
static byte[] ASCIItoEBCDIC(string asciiString)
{
byte[] asciiToEbcdicTable = new byte[256] {
0x00,0x01,0x02,0x03,0x37,0x2D,0x2E,0x2F,0x16,0x05,0x25,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x3C,0x3D,0x32,0x26,0x18,0x19,0x3F,0x27,0x1C,0x1D,0x1E,0x1F,
0x40,0x5A,0x7F,0x7B,0x5B,0x6C,0x50,0x7D,0x4D,0x5D,0x5C,0x4E,0x6B,0x60,0x4B,0x61,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0x7A,0x5E,0x4C,0x7E,0x6E,0x6F,
0x7C,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,
0xD7,0xD8,0xD9,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xBA,0xE0,0xBB,0xB0,0x6D,
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xC0,0x4F,0xD0,0xA1,0x07,
0x20,0x21,0x22,0x23,0x24,0x15,0x06,0x17,0x28,0x29,0x2A,0x2B,0x2C,0x09,0x0A,0x1B,
0x30,0x31,0x1A,0x33,0x34,0x35,0x36,0x08,0x38,0x39,0x3A,0x3B,0x04,0x14,0x3E,0xFF,
0x41,0xAA,0x4A,0xB1,0x9F,0xB2,0x6A,0xB5,0xBD,0xB4,0x9A,0x8A,0x5F,0xCA,0xAF,0xBC,
0x90,0x8F,0xEA,0xFA,0xBE,0xA0,0xB6,0xB3,0x9D,0xDA,0x9B,0x8B,0xB7,0xB8,0xB9,0xAB,
0x64,0x65,0x62,0x66,0x63,0x67,0x9E,0x68,0x74,0x71,0x72,0x73,0x78,0x75,0x76,0x77,
0xAC,0x69,0xED,0xEE,0xEB,0xEF,0xEC,0xBF,0x80,0xFD,0xFE,0xFB,0xFC,0xAD,0xAE,0x59,
0x44,0x45,0x42,0x46,0x43,0x47,0x9C,0x48,0x54,0x51,0x52,0x53,0x58,0x55,0x56,0x57,
0x8C,0x49,0xCD,0xCE,0xCB,0xCF,0xCC,0xE1,0x70,0xDD,0xDE,0xDB,0xDC,0x8D,0x8E,0xDF};
byte[] ebcdicBinary = new byte[asciiString.Length];
for (int pos = 0; pos < asciiString.Length; ++pos)
{
int ebcdicIndex = asciiString[pos];
ebcdicBinary[pos] = asciiToEbcdicTable[ebcdicIndex];
}
return ebcdicBinary;
}
Try like below code
public string ConvertASCIItoEBCDIC(string strASCIIString)
{
int[] a2e = new int[256]{
0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
64, 79,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97,
240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111,
124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214,
215,216,217,226,227,228,229,230,231,232,233, 74,224, 90, 95,109,
121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150,
151,152,153,162,163,164,165,166,167,168,169,192,106,208,161, 7,
32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,225,
65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
88, 89, 98, 99,100,101,102,103,104,105,112,113,114,115,116,117,
118,119,120,128,138,139,140,141,142,143,144,154,155,156,157,158,
159,160,170,171,172,173,174,175,176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,202,203,204,205,206,207,218,219,
220,221,222,223,234,235,236,237,238,239,250,251,252,253,254,255
};
char chrItem = Convert.ToChar("0");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strASCIIString.Length; i++)
{
try
{
chrItem = Convert.ToChar(strASCIIString.Substring(i, 1));
sb.Append(Convert.ToChar(a2e[(int)chrItem]));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return string.Empty;
}
}
string result = sb.ToString();
sb = null;
return result;
}
and check the saple code on these links
http://kseesharp.blogspot.com/2007/12/convert-ascii-to-ebcdic.html
http://forums.asp.net/t/167516.aspx
http://www.yoda.arachsys.com/csharp/ebcdic/
http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/c2b074fd-4293-4bf4-b7fa-1803fc625d43

Categories

Resources