I have a class which contains multiple properties of type Int32:
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
.
.
.
public int Cn { get; set; }
}
I want to sum all this properties. Instead of doing:
int sum = C1 + C2 + C3 + ... + Cn
is there a more efficient/elegant method?
You can fake it, but I'm not sure how useful it is:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var test = new MyClass();
// ...
int sum = test.All().Sum();
}
}
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
// ...
public int Cn { get; set; }
public IEnumerable<int> All()
{
yield return C1;
yield return C2;
yield return C3;
// ...
yield return Cn;
}
}
}
If you really want to perform the sum without having to type each property you can use reflection to iterate through your properties but this is involves a big performance cost. However, for fun you can do something like this:
var item = new MyClass();
// Populate the values somehow
var result = item.GetType().GetProperties()
.Where(pi => pi.PropertyType == typeof(Int32))
.Select(pi => Convert.ToInt32(pi.GetValue(item, null)))
.Sum();
PS: Don't forget to add using System.Reflection; directive.
Maybe you can use an array or a data structure which has the IEnumarable interfaces vs a custom class. Then you can use linq to do Sum().
If there's a strong enough need to store the values in separate members (properties, fields), then yes, that's the only way. If you have a list of numbers however, store them in a list, not in separate members.
Or, ugly:
new[]{C1,C2,C3,C4}.Sum()
But more characters than the single "+" anyway.
public class MyClass
{
readonly int[] _cs = new int[n];
public int[] Cs { get { return _cs; } }
public int C1 { get { return Cs[0]; } set { Cs[0] = value; } }
public int C2 { get { return Cs[1]; } set { Cs[1] = value; } }
public int C3 { get { return Cs[2]; } set { Cs[2] = value; } }
.
.
.
public int Cn { get { return Cs[n-1]; } set { Cs[n-1] = value; } }
}
Now you can use Enumerable.Sum with MyClass.Cs, and you can still map C1, C2, ... to database fields.
Related
I have a class that contains Range[] as property and Range class is a self referencing class. I used [JsonIgnore] to prevent StackoverflowException but it works for only Serialize not Deserialize. How can I fix this?
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace testoverflow
{
class Program
{
public static void Main(string[] args)
{
GlobalVariable.Json = "[{\"TotalBytesReceived\":0,\"Id\":\"b03750fb291a46708f8e1a7409553075\",\"NofThread\":8,\"Speed\":0,\"Progress\":0.0,\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\Downloads\",\"RangeDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"Url\":\"http://ipv4.download.thinkbroadband.com/20MB.zip\",\"Ranges\":[{\"Start\":0,\"End\":9223372036854775806,\"TotalBytesReceived\":0,\"IsDownloaded\":false,\"FileId\":\"87cd7715dc0740c1b82ddd681bf2523d\",\"Size\":9223372036854775807,\"Status\":4,\"IsIdle\":false,\"SaveDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\\\\87cd7715dc0740c1b82ddd681bf2523d\",\"Md5Checksum\":null}],\"Info\":null,\"DownloadRequestMessage\":null}]";
var a = new MTDO();
Console.WriteLine(GlobalVariable.Json);
Console.ReadKey(true);
}
public static class GlobalVariable
{
public static string Json { get; set; }
}
public class MTDO
{
public MTDO()
{
Ranges = new Range[]
{
new Range(0L, 100L, ""),
new Range(101L, 200L, "")
};
Id = Guid.NewGuid().ToString("N");
Reminder.AddOrUpdate(this);
}
public string Id { get; set; }
public Range[] Ranges{ get; set; }
}
public class Range
{
public long Start { get; set; }
public long End { get; set; }
public string SaveDir { get; set; }
public long TotalBytesReceived{ get; set; }
public Range(long start, long end, string saveDir)
{
this.Start = start;
this.End = end;
this.SaveDir = Guid.NewGuid().ToString();
}
[JsonIgnore]
public Range Remaining
{
get
{
return new Range(Start + TotalBytesReceived, End, SaveDir);
}
}
}
public class Reminder
{
public Reminder()
{
}
public static void AddOrUpdate(MTDO mtdo)
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
var exists = list.Any(x => x.Id == mtdo.Id);
if (!exists)
list.Add(mtdo);
else
{
var i = list.Select((x, j) => new {val = x, index = j})
.First(x => x.val.Id == mtdo.Id).index;
list[i] = mtdo;
}
WriteJson(list);
}
public static List<MTDO> ReadList()
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
return list;
}
static string Read()
{
try
{
return GlobalVariable.Json;
}
catch
{
return "";
}
}
static void WriteJson(List<MTDO> list)
{
GlobalVariable.Json = JsonConvert.SerializeObject(list);
}
}
}
}
UPDATE: I have updated myquestion adding minimum reproducable code in Console Application. You can copy/paste and run directly.
The problem is that you have an infinite recursion:
You call MTDO constructor
Inside MTDO constructor you call Reminder.AddOrUpdate(this);
Inside that method you have var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
Which calls MTDO constructor again (step 1)
These steps keep repeating until you get StackOverflowException.
Declarations:
interface I
{
int i { get; set; }
}
class C : I
{
public int i { get; set; }
}
Code:
C c = new C();
c.i = 10;
PropertyInfo pi1 =
c.
GetType().
GetInterfaces().
SelectMany(t => t.GetProperties()).
ToArray()[0];
PropertyInfo pi2 =
c.
GetType().
GetProperties()[0];
object v1 = pi1.GetValue(c);
object v2 = pi2.GetValue(c);
Hey, v1 == v2, pi1 != pi2, but GetValue obviously calls same method. How can I know in my code that pi1 and pi2 call same method body?
You can use Type.GetInterfaceMap() to get a mapping between interface members and the implementing members for a specific type. Here's an example:
using System;
using System.Linq;
using System.Threading;
interface I
{
int Value { get; set; }
}
class C : I
{
public int Value { get; set; }
}
public class Test
{
static void Main()
{
var interfaceGetter = typeof(I).GetProperty("Value").GetMethod;
var classGetter = typeof(C).GetProperty("Value").GetMethod;
var interfaceMapping = typeof(C).GetInterfaceMap(typeof(I));
var interfaceMethods = interfaceMapping.InterfaceMethods;
var targetMethods = interfaceMapping.TargetMethods;
for (int i = 0; i < interfaceMethods.Length; i++)
{
if (interfaceMethods[i] == interfaceGetter)
{
var targetMethod = targetMethods[i];
Console.WriteLine($"Implementation is classGetter? {targetMethod == classGetter}");
}
}
}
}
That prints Implementation is classGetter? True - but if you change the code so that fetching I.Value doesn't call C.Value, e.g. by adding a base class so that C.Value is a new property, not an implementation of I.Value:
interface I
{
int Value { get; set; }
}
class Foo : I
{
public int Value { get; set; }
}
class C : Foo
{
public int Value { get; set; }
}
... then it will print Implementation is classGetter? False.
I am trying to map one object to another but I am getting a problem while mapping an empty string to type int or a non integer string to int, so what I want that if I such exceptions occur it must assign some default value to it, let say -1.
for example we have a class A and Class B
Class A
{
public string a{get;set;}
}
Class B
{
public int a{get;set;}
}
Now if we map from class A to B using default rule it will through exception if string is empty or non integer.
Please help me fix this problem.
Thanks in advance.
I think this is what you're after.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using NUnit.Framework;
namespace StackOverFlowAnswers
{
public class LineItem
{
public int Id { get; set; }
public string ProductId { get; set; }
public int Amount { get; set; }
}
public class Model
{
public int Id { get; set; }
public string ProductId { get; set; }
public string Amount { get; set; }
}
public class AutoMappingTests
{
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
Mapper.CreateMap<Model, LineItem>()
.ForMember(x => x.Amount, opt => opt.ResolveUsing<StringToInteger>());
}
[Test]
public void TestBadStringToDefaultInteger()
{
// Arrange
var model = new Model() {Id = 1, ProductId = "awesome-product-133-XP", Amount = "EVIL STRING, MWUAHAHAHAH"};
// Act
LineItem mapping1 = Mapper.Map<LineItem>(model);
// Assert
Assert.AreEqual(model.Id, mapping1.Id);
Assert.AreEqual(model.ProductId, mapping1.ProductId);
Assert.AreEqual(0, mapping1.Amount);
// Arrange
model.Amount = null; // now we test null, which we said in options to map from null to -1
// Act
LineItem mapping2 = Mapper.Map<LineItem>(model);
// Assert
Assert.AreEqual(-1, mapping2.Amount);
}
}
public class StringToInteger : ValueResolver<Model, int>
{
protected override int ResolveCore(Model source)
{
if (source.Amount == null)
{
return -1;
}
int value;
if (int.TryParse(source.Amount, out value))
{
return value; // Wahayy!!
}
return 0; // return 0 if it could not parse!
}
}
}
Well the above code works too while i am sharing one code which i made myself as it works too
public class StringToIntTypeConverter : ITypeConverter<string, int>
{
public int Convert(ResolutionContext context)
{
int result;
if (!int.TryParse(context.SourceValue.ToString(), out result))
{
result = -1;
};
return result;
}
}
public class Item
{
public List<int> val { get; set; }
public double support { get; set; }
}
I declare variable:
List<Item> t = new List<Item>();
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
var b = new Item();
b.val = t[0].val;
b.support=t[0].support;
t.Contain(b) // return false???
I'm try with linq
t.Any(a=>a.val==b.val) // I'm get error Expression cannot contain lambda expressions
3 possibilities come to mind:
You could implement IEquatable<T>:
public class Item: IEquatable<Item>
{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item other)
{
return
this.support == other.support &&
this.val.SequenceEqual(other.val);
}
}
and now t.Contains(b) will return true.
If you cannot modify the Item class you could write a custom EqualityComparer:
public class ItemEqualityComparer : IEqualityComparer<Item>
{
private ItemEqualityComparer()
{
}
public static IEqualityComparer<Item> Instance
{
get
{
return new ItemEqualityComparer();
}
}
public bool Equals(Item x, Item y)
{
return
x.support == y.support &&
x.val.SequenceEqual(y.val);
}
public int GetHashCode(Item obj)
{
int hash = 27;
hash += (13 * hash) + obj.support.GetHashCode();
foreach (var item in obj.val)
{
hash += (13 * hash) + item.GetHashCode();
}
return hash;
}
}
and then t.Contains(b) will also return true.
Or if you prefer simply do it naively:
List<Item> t = new List<Item>();
t.Add(new Item { val = new List<int>(){1,2,3}, support=.1 });
var b = new Item();
b.val = t[0].val;
b.support = t[0].support;
bool equals = t.All(item => item.support == b.support && item.val.SequenceEqual(b.val));
Console.WriteLine(equals);
Your t.Any(a=>a.val == b.val) is correct.
The error you get is from the quick watch or expression window in the debugger, not from the compiler. Visual Studio's expression evaluator does not handle lambdas. However, it's still valid c# code, and will do what you want.
It's your earlier line that's a problem:
t.Add(new Item(){val = new List<int>(){1,2,3};support=.1);
This is a mixture of various different bits of syntax. It should be:
t.Add(new Item(){val = new List<int>(){1,2,3}, support=.1});
... although preferably with better property names, etc. Then the rest should work - although you need to do something with the result of Any. The Any call itself is valid. Here's a short but complete program which works:
using System;
using System.Collections.Generic;
using System.Linq;
public class Item
{
public List<int> Values { get; set; }
public double Support { get; set; }
}
class Test
{
static void Main()
{
List<Item> list = new List<Item>
{
new Item { Values = new List<int>{1, 2, 3},
Support = 0.1 }
};
var check = new Item { Values = list[0].Values,
Support = list[0].Support };
bool found = list.Any(a => a.Values == check.Values);
Console.WriteLine(found);
}
}
Note that this is performing a reference comparison between the two lists - if you created a different list with the same values (1, 2, 3), that wouldn't be found. You'd need to use a.Values.SequenceEqual(b.Values) or something similar.
Your Item class should implemenet the IEquatable interface:
class Item : IEquatable<Item>{
public List<int> val { get; set; }
public double support { get; set; }
public bool Equals(Item item){
return this.support.Equals(item.support) && this.val.SequenceEqual(item.val);
}
}
Then the Contains() method should work well.
You can correct your "t.Contain(b)" to t.Contains(b, new ItemEqualityComparer()) from System.Linq where ItemEqualityComparer will be your class, which will implement IEqualityComparer<Item>
Hi I have had to use interfaces before but ive been told i need to implement icomparable in this instance. see below:
internal class doorItem : IComparable
{
public int CompareTo(doorItem other)
{
// The temperature comparison depends on the comparison of the
// the underlying Double values. Because the CompareTo method is
// strongly typed, it is not necessary to test for the correct
// object type.
return GetNumber(productSize).CompareTo(GetNumber(other.productSize));
}
public string variations { get; set; }
public double pricerange { get; set; }
public string viewDetailsLink { get; set; }
public string height { get; set; }
public string width { get; set; }
public string productSize { get; set; }
public string productImage { get; set; }
public int countItemsOnSale { get; set; }
public string optionFor35Product { get; set; }
private int GetNumber(string str)
{
//this method gets the int out of the string
int length = str.Length;
string output = String.Empty;
int test = 0;
bool err = false;
for (int i = 0; i <= length; i++)
{
try
{
test = Convert.ToInt32(str.Substring(i, 1));
}
catch
{
err = true;
}
if (!err)
output += str.Substring(i, 1);
else
break;
}
return Convert.ToInt32(output);
}
}
above is the class i have created, door sizes are returned like this: 4dr, 5dr, 6dr etc.. then the getnumber method gets the int out of the string.
i have a generic list in of my custom class in the main method like this:
List<doorItem> d = new List<doorItem>();
i cant work out how to order this list by door size.... PLEASE HELP
It's easiest to do this using LINQ. Then you don't even need to implement IComparable.
var sortedList = doorList.OrderBy( d => d.GetNumber(d.productSize ).ToList();
And make GetNumber public inside the doorItem class.
I don't know if performance is important, but that method for getting the number is pretty horrible, exceptions should only be used in exceptional circumstances! Suggest something like this
StringBuilder sb = new StringBuilder();
foreach (char c in str)
{
if (Char.IsNumber(c))
{
sb.append(c);
}
}
return Convert.ToInt32(sb.ToString());
For sorting you can do what stecya has suggested, or you could convert this method to a property and sort directly.
public int Size
{
get
{
return GetNumber(this.productSize);
}
}
...
d.OrderBy(x=>x.Size);