C# Custom Comparer with Comparison delegate - c#

I'm trying to sort a custom BindingList. But i came across the problem that my Comparer does not recognize the properties of my class.
The "x.Code_PK_OriginalValue" is not recognized. The weird thing is that intellisense marks "Begrenzingen" in Comparer class different as "Begrenzingen" in the first code block beneath.
BindingListX<Begrenzingen> lst = new BindingListX<Begr.....;
lst.OrderBy(t => t, new CustomComparer<Begrenzingen>());
.
public class CustomComparer<Begrenzingen> : IComparer<Begrenzingen>
{
private readonly Comparison<Begrenzingen> _comparison;
public CustomComparer()
{
_comparison = new Comparison<Begrenzingen>(
(Begrenzingen x, Begrenzingen y) =>
{
return x.Code_PK_OriginalValue.CompareTo(y.Code_PK_OriginalValue);
}
);
}
public int Compare(Begrenzingen x, Begrenzingen y)
{
return _comparison(x, y);
}
}
 .
public class BindingListX<T> : BindingList<T>
{
public void OrderBy(Func<T,T> keySelector, IComparer<T> comparer)
{
this.Items.OrderBy(keySelector, comparer);
}
}
.
public class Begrenzingen : DefaultTable, IComparable<Begrenzingen>
{
public Begrenzingen()
{ //New -> Insert DB
Code_PK_OriginalValue = -1;
isDeleted = false;
}
public decimal Code_PK_OriginalValue { get; set; }
public decimal Code_PK { get; set; }
public string Naam { get; set; }
public decimal? SeqLayer { get; set; }
public Boolean isDeleted { get; set; }
public string SeqLayerDisplayValue {
get {
if (SeqLayer == null) return string.Empty;
return (from sdo in MainWindow.Main.SdoLayers where sdo.SeqLayer == this.SeqLayer select sdo.DisplayValue).First();
}
}
public override string ToString()
{
return String.Format("{0};{1};{2};{3}", Code_PK_OriginalValue, Code_PK, Naam, SeqLayer);
}
public int CompareTo(Begrenzingen o)
{
return Code_PK.CompareTo(o.Code_PK);
}
}

How about just lst.OrderBy(t => t.Code_PK_OriginalValue);

Related

Add subtype objects to list of supertype, then return list of subtypes from list of supertypes

I have 3 interfaces.
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
IEquipable is implemented by the classes Helmet and Bow, and IConsumable is implemented by classes Potion and Food.
Then, I have a class with a property which contains a List of IItem, and proceed to add a few items of both IEquipable and IConsumable after instantiating it.
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Program.cs
...
Character char = new Character();
char.AddItem(new Potion());
char.AddItem(new Food());
char.AddItem(new Helmet());
char.AddItem(new Bow());
...
Is there a way I can get a List of all IEquipable members from the List of IItems, each AS IEquipable?
I want to do something like
...
List<IEquipable> equipmentList = //do something to char.Items and get all items of type IEquipable.
IEquipment equipment = equipmentList.First(...)
equipment.Equip();
...
I've tried using List<IEquipable> equipmentList = char.Items.OfType<IEquipable>().ToList() but the resulting list ends up empty.
I implemented (and fixed minor typos in) your code like this:
void Main()
{
Character character = new Character();
character.AddItem(new Potion());
character.AddItem(new Food());
character.AddItem(new Helmet());
character.AddItem(new Bow());
List<IEquipable> equipmentList = character.Items.OfType<IEquipable>().ToList();
}
public class Potion : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Food : IConsumable
{
public string Name { get; set; }
public void Use()
{
throw new NotImplementedException();
}
}
public class Helmet : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public class Bow : IEquipable
{
public string Name { get; set; }
public void Equip()
{
throw new NotImplementedException();
}
}
public interface IItem
{
string Name { get; set; }
}
public interface IEquipable : IItem
{
void Equip();
}
public interface IConsumable : IItem
{
void Use();
}
public class Character
{
public List<IItem> Items { get; private set; }
public Character()
{
this.Items = new List<IItem>();
}
public void AddItem(IItem item)
{
this.Items.Add(item);
}
}
Your exact code (albeit char renamed to character) works perfectly fine. The equipmentList ends up with two elements. The issue you're seeing, i.e. "the resulting list ends up empty", is not reproducible with the code you've posted.
You can use the OfType method
Filters the elements of an IEnumerable based on a specified type.
Signature
public static IEnumerable<TResult> OfType<TResult> (this IEnumerable source)
Usage
var equipable = Character.Items.OfType<IEquipable>();
Or encapsulate it as a method in the instance or an extension method if you like
So it does work like I wanted. My actual code just had another issue and I'm a dummy for not actually posting that. So here it is, for future reference.
using System.Collections.Generic;
using RolePlayGame.Library.Items.Backstage;
using System.Linq;
using System.Text;
using System;
namespace RolePlayGame.Library.Characters.Backstage
{
public class Inventory
{
public List<IItem> StoredItems { get; private set; }
public List<EquippedItem> Gear { get; private set; }
public Inventory()
{
this.StoredItems = new List<IItem>();
this.Gear = new List<EquippedItem>();
}
public bool HasItem(string name)
{
return this.StoredItems.Exists(item => item.Name == name);
}
public bool HasItem(IItem item)
{
return this.StoredItems.Contains(item);
}
public void RemoveItem(string name)
{
int firstIndex = this.StoredItems.FindIndex(item => item.Name == name);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void RemoveItem(IItem item)
{
int firstIndex = this.StoredItems.IndexOf(item);
if (firstIndex != -1)
{
this.StoredItems.RemoveAt(firstIndex);
}
}
public void AddItem(IItem item, int quantity)
{
for (int i = 0; i < quantity; i++)
{
this.StoredItems.Add(item);
}
}
public void AddItem(IItem item)
{
this.StoredItems.Add(item);
}
public bool CheckEquipmentSlot(EquipmentSlot slot)
{
return this.Gear.Exists(item => item.UsedSlots.Contains(slot));
}
public bool HasEquipment(IEquipment equipment)
{
return this.Gear.Exists(item => item.Item == equipment);
}
public void AddEquipment(IEquipment equipment)
{
IEquipment alreadyEquipped;
foreach (EquipmentSlot slot in equipment.SlotsUsed)
{
if (this.Gear.Exists(item => item.UsedSlots.Contains(slot)))
{
alreadyEquipped = this.Gear.Find(item => item.UsedSlots.Contains(slot)).Item;
this.RemoveEquipment(slot);
this.StoredItems.Add(alreadyEquipped);
}
}
EquippedItem newEquipment = new EquippedItem(equipment);
this.Gear.Add(newEquipment);
}
public void RemoveEquipment(EquipmentSlot slot)
{
this.Gear.RemoveAll(equipment => equipment.UsedSlots.Contains(slot));
}
public int GetAttributeBonusTotal(AttributeType attribute)
{
int bonusTotal = 0;
foreach (IEquipment item in this.StoredItems.OfType<IEquipment>().ToList())
{
bonusTotal += item.GetAttributeBonus(attribute);
}
return bonusTotal;
}
public int GetCarryWeight()
{
int totalWeight = 0;
foreach (IItem item in StoredItems)
{
totalWeight += item.Weight;
}
return totalWeight;
}
public string GearToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Equipped Gear:");
foreach (EquippedItem equipment in this.Gear)
{
builder.Append($"\n {equipment.Item.Name}");
}
return builder.ToString();
}
public string ItemsToString()
{
StringBuilder builder = new StringBuilder();
builder.Append(" Inventory:");
foreach (IItem item in this.StoredItems.Distinct())
{
builder.Append($"\n {item.Name} x {this.StoredItems.FindAll(value => value == item).Count()}");
}
return builder.ToString();
}
public int GetDefenseRateAgainstTypeTotal(DamageType againstType)
{
int rate = 0;
List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList();
foreach (IOutfit item in outfits)
{
rate += item.GetDefenseRateAgainstType(againstType);
}
return rate;
}
}
}
One of the last lines has the problem (now fixed). List<IOutfit> outfits = this.Gear.Select(value => value.Item).OfType<IOutfit>().ToList(); used to be List<IOutfit> outfits = this.Gear.OfType<IOutfit>().ToList();. But Gear is of type List<EquippedItem>, and EquippedItem is not an implementation of IItem.
Here is EquippedItem.cs
using RolePlayGame.Library.Items.Backstage;
using System.Collections.Generic;
namespace RolePlayGame.Library
{
public class EquippedItem
{
public List<EquipmentSlot> UsedSlots { get; set; }
public IEquipment Item { get; set; }
public EquippedItem(IEquipment equipment)
{
this.Item = equipment;
this.UsedSlots = equipment.SlotsUsed;
}
}
}
I needed to select the Item property from the items inside Gear as another list before doing the type filtering with .OfType<IOutfit>(). That's where .Select(value => value.Item) enters the stage.
So that's that. I'll learn to post actual code for future questions.

How to get entity by specific field (not primary key)?

I have done get data by Id (primary key) with success. But if I call Get by another field, why is it always Id that is used?
Here is my code:
ITempatAppService.cs
public interface ITempatAppService:IApplicationService
{
GetTempatOutput GetTempatById(GetTempatInput input);
GetTempatOutput GetTempatByIdKategori(GetTempatKategori input);
}
GetTempatInput.cs
public class GetTempatInput
{
public int Id { get; set; }
}
GetTempatOutput.cs
public class GetTempatKategori
{
public int IdKategori { get; set; }
}
TempatAppService.cs
public class TempatAppService:ApplicationService,ITempatAppService
{
private readonly ITempatManager _tempatManager;
public TempatAppService(ITempatManager tempatManager)
{
_tempatManager = tempatManager;
}
public GetTempatOutput GetTempatById(GetTempatInput input)
{
var getTempat = _tempatManager.GetTempatById(input.Id);
GetTempatOutput output = Mapper.Map<MasterTempat, GetTempatOutput>(getTempat);
return output;
}
public GetTempatOutput GetTempatByIdKategori(GetTempatKategori input)
{
var getTempat = _tempatManager.GetTempatByIdKategori(input.IdKategori);
GetTempatOutput output = Mapper.Map<MasterTempat, GetTempatOutput>(getTempat);
return output;
}
}
Here is my TempatManager.cs:
public class TempatManager : DomainService, ITempatManager
{
private readonly IRepository<MasterTempat> _repositoryTempat;
public TempatManager(IRepository<MasterTempat> repositoryTempat)
{
_repositoryTempat = repositoryTempat;
}
public MasterTempat GetTempatById(int Id)
{
return _repositoryTempat.Get(Id);
}
public MasterTempat GetTempatByIdKategori(int IdKategori)
{
return _repositoryTempat.Get(IdKategori);
}
}
Naming the parameter IdKategori doesn't make it search by that column. Do this:
public MasterTempat GetTempatByIdKategori(int IdKategori)
{
return _repositoryTempat.GetAll().First(t => t.IdKategori == IdKategori);
}
To take the list of the selected kategori.
public List<MasterTempat> GetTempatByIdKategori(int IdKategori)
{
return _repositoryTempat.GetAll().Where(t => t.IdKategori == IdKategori).ToList();
}

How do you migrate from a list to a class C# DataContract Serialization?

How can I migrate a configuration to a new class from a list of bools? Previously it used a list of bool, but the list was being abused as a class, with each index having a specific meaning like a field.
I want to migrate it from a List, to a class that instead acts as the list for serialization purposes, but exposes normal fields to the rest of the application.
How can I write class ListEmulator so that it serializes out to a list, without introducing new xml tags?
old code
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new List<bool>();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public List<bool> AList { get; set; }
}
}
new code.
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AListEmulator = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public ListEmulator AListEmulator { get; set; }
}
}
public class ListEmulator
{
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
}
The reason a list is needed, is there is old migration code that needs to be ported for when there was only 1 element, then 2, 3, 4 with different defaults for each. If it weren't for the fact that I have existing deployed configuration files in the original format, it would probably be time for them to all be named in the XML individually. However, I need to retain the current format for now. For the sake of migration I'm wondering how I can accomplish the above.
One option would be for your ListEmulator to inherit from Collection<bool>, and then add specific named properties to access elements in the array, like so:
public class ListEmulator : Collection<bool>
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
void AddAllDefaults()
{
// Customize the code here to upgrade old collections with fewer than 4 elements to the current 4-element format.
if (Count < 1)
Add(IsPlannedDefault);
if (Count < 2)
Add(IsCompletedDefault);
if (Count < 3)
Add(IsRemainingDefault);
if (Count < 4)
Add(IsSerialDefault);
}
public ListEmulator() { }
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get { return this.ElementAtOrDefault(0, IsPlannedDefault); } set { AddAllDefaults(); this[0] = value; } }
public bool IsCompleted { get { return this.ElementAtOrDefault(1, IsCompletedDefault); } set { AddAllDefaults(); this[1] = value; } }
public bool IsRemaining { get { return this.ElementAtOrDefault(2, IsRemainingDefault); } set { AddAllDefaults(); this[2] = value; } }
public bool IsSerial { get { return this.ElementAtOrDefault(3, IsSerialDefault); } set { AddAllDefaults(); this[3] = value; } }
protected override void InsertItem(int index, bool item)
{
if (index > 3)
throw new ArgumentOutOfRangeException("index > 3");
base.InsertItem(index, item);
}
}
Then in your Configuration simply replace List<bool> with ListEmulator, keeping the old element name:
[DataMember]
public ListEmulator AList { get; set; }
Because this type implements IEnumerable<T>, the DataContractSerializer will serialize it as a collection rather than as an object with properties. (You might want to change the class name since it's really not a list emulator at this point.) However, this only works if you do not add any initial values to the collection from within the default constructor.
Another option would be to add a surrogate property to Configuration that handles the necessary conversions, and mark the ListEmulator AList as not serialized:
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember(Name = "AList")]
bool[] AlistArray
{
get
{
return AList == null ? null : AList.ToArray();
}
set
{
AList = new ListEmulator(value);
}
}
[IgnoreDataMember] // Do not serialize this property directly
public ListEmulator AList { get; set; }
}
public class ListEmulator
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
public ListEmulator(IList<bool> list)
{
IsPlanned = list.ElementAtOrDefault(0, IsPlannedDefault);
IsCompleted = list.ElementAtOrDefault(1, IsCompletedDefault);
IsRemaining = list.ElementAtOrDefault(2, IsRemainingDefault);
IsSerial = list.ElementAtOrDefault(3, IsSerialDefault);
}
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
public bool[] ToArray()
{
return new[] { IsPlanned, IsCompleted, IsRemaining, IsSerial };
}
}
Both options use the following extension method:
public static class ListExtensions
{
public static T ElementAtOrDefault<T>(this IList<T> list, int index, T defaultValue)
{
if (index < 0)
throw new ArgumentOutOfRangeException(string.Format("index = {0}", index));
if (list == null || index >= list.Count)
return defaultValue;
return list[index];
}
}

C# DynamoDB Query a nested property using LINQ

I've the MyTableItem class that maps a DynamoDB table.
I need to implements the GetMyTableItemsWithoutFinalStatus method that query the table by specific filters on nested property of a custom type, MyStatus.
The filter has to check if:
there's no status
status is not initialized
there's no "final" status in the status list
date is greater than today - daysFromNow
So my conditions in OR are:
StatusCount == 0
Status == null
Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0
Date > DateTime.UtcNow.AddDays(-daysFromNow)
Actually I need to get back all the items that has no status or no final status, because I've to update them.
How can I implement the condition on nested property of MyStatus object?
This is my code
[Serializable]
public class MyTableItem
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty]
public string Field1 { get; set; }
[DynamoDBProperty]
public string Field2 { get; set; }
[DynamoDBProperty]
[DynamoDBGlobalSecondaryIndexRangeKey]
public DateTime Date { get; set; }
// My complex object
[DynamoDBProperty(typeof(MyStatusConverter))]
public MyStatus Status { get; set; }
[DynamoDBProperty]
public int StatusCount { get { return Status.Count; } set { value = Status.Count; } }
}
[Serializable]
public class MyStatus : IList<MyState>
{
private readonly IList<MyState> stateList = new List<MyState>();
public PeppolDespatchAdviceState this[int index]
{
get { return stateList[index]; }
set { stateList.Insert(index, value); }
}
public int Count
{
get { return stateList.Count; }
}
public bool IsReadOnly
{
get { return stateList.IsReadOnly; }
}
// IList interface implementation...
}
[Serializable]
public class MyState
{
public string DocumentType { get; set; }
public string Status { get; set; }
public string SkipCause { get; set; }
public DateTime Date { get; set; }
}
public enum StatusEnum
{
DEFAULT,
CREATED,
DELIVERED,
UNDELIVERABLE,
RE_RECEIVED
}
#region Converter definition
public class MyStatusConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value)
{
// Implementation...
}
public object FromEntry(DynamoDBEntry entry)
{
// Implementation...
}
#endregion
public IList<MyTableItem> GetMyTableItemsWithoutFinalStatus(long id, int daysFromNow = 3)
{
try
{
List<MyTableItem> items = new List<MyTableItem>();
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig();
operationConfig.OverrideTableName = "MyTableName";
operationConfig.IndexName = "MyIndex";
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition(MyTableItemTableAttributes.StatusCount, ScanOperator.Equal, 0));
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Status, ScanOperator.IsNull));
// Here I need to add a LINQ condition: Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0 )
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Date, ScanOperator.GreaterThan, DateTime.UtcNow.AddDays(-daysFromNow)));
operationConfig.QueryFilter = conditions;
operationConfig.ConditionalOperator = ConditionalOperatorValues.Or;
DynamoDBContext context = new DynamoDBContext(DynamoDBClient);
items = context.Query<MyTableItem>(id, operationConfig).ToList();
return items;
}
catch (Exception ex)
{
throw;
}
}

Avoid having to cast with generics and a list of custom data

I have the following code for supporting a list of different types :
public enum eType
{
tInt,
tString,
tDateTime
}
public interface ICustomType<out T>
{
T Value { get; }
}
public abstract class DifferentType
{
protected DifferentType(eType type, string mnemonic)
{
Type = type;
Mnemonic = mnemonic;
}
public string Mnemonic { get; private set; }
public eType Type { get; private set; }
}
public class DateTimeType : DifferentType, ICustomType<DateTime>
{
public DateTimeType(DateTime value, string mnemonic)
: base(eType.tDateTime, mnemonic)
{
Value = value;
}
public DateTime Value { get; private set; }
}
public class IntType : DifferentType, ICustomType<int>
{
public IntType(int value, string mnemonic)
: base(eType.tInt, mnemonic)
{
Value = value;
}
public int Value { get; private set; }
}
public class StringType : DifferentType, ICustomType<string>
{
public StringType(string value, string mnemonic)
: base(eType.tString, mnemonic)
{
Value = value;
}
public string Value { get; private set; }
}
public static class UtilValue
{
public static T GetValue<T>(DifferentType customType)
{
return ((ICustomType<T>)customType).Value;
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { GetInt(), GetString(), GetDate() };
foreach (var i in values)
{
switch (i.Type)
{
case eType.tInt:
int resInt = UtilValue.GetValue<int>(i);
break;
case eType.tString:
string resString = UtilValue.GetValue<string>(i);
break;
case eType.tDateTime:
DateTime resDateTime = UtilValue.GetValue<DateTime>(i);
break;
}
}
}
private DateTimeType GetDate()
{
return new DateTimeType(new DateTime(2000, 1, 1), "MnemonicDate");
}
private IntType GetInt()
{
return new IntType(5, "MnemonicInt");
}
private StringType GetString()
{
return new StringType("ok", "MnemonicString");
}
}
and would like to avoid the cast at line return ((ICustomType<T>)customType).Value; in the UtilValue class, any idea how I can get rid of that while still keeping the design?
I am not even sure if this cast is expensive to do? My guess is most certainly.
Visitor-pattern example:
interface IDifferentTypeVisitor
{
void Visit(DateTimeType dt);
void Visit(StringType st);
}
class DifferentType
{
public abstract void Accept(IDifferentTypeVisitor visitor);
}
class DateTimeType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class StringType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class SomeVisitor : IDifferentTypeVisitor
{
public void Visit(DateTimeType dt)
{
//DateTime resDateTime = dt.Value; Or similar
}
public void Visit(StringType st)
{
//string resString = st.Value; Or similar
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { /* Content */ };
var visitor = new SomeVisitor();
foreach (var i in values)
{
i.Accept(visitor);
}
}
}
In C# 4 with dynamic it's possible to save some code by adding this to DifferentType:
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit((dynamic)this);
}
and then delete all other Accept methods. It hurts performance but it looks better ;-)

Categories