Dynamically adding properties to an object in c# - c#

I have a problem:
public class PaginationSet
{
public int TotalItemCount { get; set; }
public int Page { get; set; }
public int Amount { get; set; }
public string Sort { get; set; }
public string Order { get; set; }
/// <summary>
/// This is used to store all the above information in, while still maintaining the automated index count from the internal for loop link builder.
///
/// Don't forget to pass the index into this!
/// </summary>
public Func<int, object> PaginationLinkData
{
get
{
return index => new
{
page = index, // This is the internal pointer part that is used currently by Bootstrap pagination function
amount = this.Amount,
sort = this.Sort,
order = this.Order
};
}
}
}
this.Sort and this.Order are sometimes null. If they are, I would like to not place them inside the returning Func<int,object>... How do i go about doing this?
It might look something like this:
public Func<int, object> PaginationLinkData
{
get
{
Func<int,object> something = index => new
{
page = index, // This is the internal pointer part that is used currently by Bootstrap pagination function
amount = this.Amount
};
if( this.Sort != null )
{
something.sort = this.Sort,
something.order= this.Order
}
return something;
}
}
}

Try using expando object...
public Func<int, object> PaginationLinkData
{
get
{
return index =>
{
dynamic obj = new ExpandoObject();
obj.page = index;
obj.amount = this.Amount;
if (this.Sort != null)
{
obj.sort = this.Sort;
}
if (this.Order != null)
{
obj.order = this.Order;
}
return obj;
};
}
}

Can't you just do something like this?
public Func<int, object> PaginationLinkData
{
get
{
if( this.Sort != null )
{
return index => new
{
page = index, // This is the internal pointer part that is used currently by Bootstrap pagination function
amount = this.Amount,
sort = this.Sort,
order = this.Order
};
}
else
{
return index => new
{
page = index, // This is the internal pointer part that is used currently by Bootstrap pagination function
amount = this.Amount,
};
}
}
}

I am guessing you are serializing to JSon somewhere. If so and you can use dynamic why not:
/// <summary>
/// This is used to store all the above information in, while still maintaining the automated index count from the internal for loop link builder.
///
/// Don't forget to pass the index into this!
/// </summary>
public Func<int, object> PaginationLinkData
{
get
{
dynamic res = new ExpandoObject();
res.amount = Amount;
if (Sort != null) res.sort = Sort;
if (Order != null) res.order = Order;
return index =>
{
res.page = index;
return res;
};
}
}

Related

LongListSelector acting strange

I’m experiencing a problem with the longlistselector witch is a bit strange... I’m reading a list asynchronously on a multi Pivot page, and if I don’t change the pivot until the resulto f the list Reading, it will create the contacts list successfuly ( in a longlistselector on the pivot item number 3 ) and when I go to that pivot the contacts list is displayed withou any problems, but when I open the Page and change the pivot before the longlistselector is created when the asychronous function returns the results and fills the longlistselector on pivot no.3 the contacts wont get updated ( when I go to pivot 3 no contacts are shown)...
I’ll post my code so you can have a clearer picture of the situation and maybe figure out what is happening.
The code is based in the PhoneToolkit LongListSelector example (buddies list)
public partial class Feeds : PhoneApplicationPage
{
bool isLoading = false;
bool loadingFilmates = true;
public Feeds()
{
InitializeComponent();
// ...
Loaded += FeedsPage_Loaded;
SystemTray.ProgressIndicator = new ProgressIndicator();
DataContext = this;
getFilmatesList();
longlistFilmates.SelectionChanged += FilmateSelectionChanged;
// ...
}
private async void getFilmatesList()
{
Feed userFilmates = await Feed.GetFilmates(App.Current.AppUser, App.Current.WSConfig, 0, "", 10000); // read feeds from webservice
Filmates = AlphaKeyGroup<StayObjectFilmates>.CreateGroups(AllFilmates.GetCurrent(userFilmates), CultureInfo.CurrentUICulture, (p) => { return p.Name; }, true);
//longlistFilmates.Visibility = System.Windows.Visibility.Collapsed;
longlistFilmates.Visibility = System.Windows.Visibility.Visible;
longlistFilmates.UseLayoutRounding = true;
pivotFeed.Visibility = System.Windows.Visibility.Collapsed;
pivotFeed.Visibility = System.Windows.Visibility.Visible;
}
}
Notice that I’ve even tried changing the Visibility property when it loads to force a re-render on the screen and it didn’t work.
This is the StayObjectFilmates class:
public class StayObjectFilmates
{
public string Img { get; private set; }
public string Name { get; private set; }
public string UserId { get; private set; }
public string Id { get; set; }
public User user { get; set; }
public StayObjectFilmates()
{
//Img = "";
//Name = "";
//Id = "";
}
public StayObjectFilmates(string p_img, string p_name, string p_Id)
{
Img = p_img;
Name = p_name;
UserId = p_Id;
}
public StayObjectFilmates(User p_user)
{
user = p_user;
}
public static string GetNameKey(StayObjectFilmates filmate)
{
char key = char.ToLower(filmate.Name[0]);
if (key < 'a' || key > 'z')
{
key = '#';
}
return key.ToString();
}
public static int CompareByName(object obj1, object obj2)
{
StayObjectFilmates p1 = (StayObjectFilmates)obj1;
StayObjectFilmates p2 = (StayObjectFilmates)obj2;
int result = p1.Name.CompareTo(p2.Name);
if (result == 0)
{
result = p1.Img.CompareTo(p2.Img);
}
return result;
}
}
This is the AllFilmates class:
public class AllFilmates : IEnumerable<StayObjectFilmates>
{
private static Dictionary<int, StayObjectFilmates> _filmateLookup;
private static AllFilmates _instance;
private Feed filmates;
// public List<StayObjectFilmates> Filmates { get; private set; }
public static AllFilmates GetCurrent(Feed p_filmates)
{
if (_instance == null)
{
_instance = new AllFilmates();
}
_instance.filmates = p_filmates;
return _instance;
}
public static AllFilmates Current
{
get
{
return _instance ?? (_instance = new AllFilmates());
}
}
public StayObjectFilmates this[int index]
{
get
{
StayObjectFilmates filmate;
_filmateLookup.TryGetValue(index, out filmate);
return filmate;
}
}
#region IEnumerable<StayObjectFilmates> Members
public IEnumerator<StayObjectFilmates> GetEnumerator()
{
EnsureData();
return _filmateLookup.Values.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
EnsureData();
return _filmateLookup.Values.GetEnumerator();
}
#endregion
private void EnsureData()
{
if (_filmateLookup == null)
{
_filmateLookup = new Dictionary<int, StayObjectFilmates>();
if (filmates != null)
{
int i = 0;
foreach (var item in filmates.itemsList)
{
User friend = item as User;
string userphoto = (friend.photo == null) ? "Images/avatar.jpg" : friend.photo;
StayObjectFilmates f = new StayObjectFilmates(userphoto, friend.fullName, i.ToString());
_filmateLookup[i] = f;
i++;
}
}
}
}
}
And this is the AlphaKeyGroup.cs file :
public class AlphaKeyGroup<T> : List<T>
{
private const string GlobeGroupKey = "\uD83C\uDF10";
/// <summary>
/// The delegate that is used to get the key information.
/// </summary>
/// <param name="item">An object of type T</param>
/// <returns>The key value to use for this object</returns>
public delegate string GetKeyDelegate(T item);
/// <summary>
/// The Key of this group.
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Public constructor.
/// </summary>
/// <param name="key">The key for this group.</param>
public AlphaKeyGroup(string key)
{
Key = key;
}
public AlphaKeyGroup(IGrouping<string, T> grouping)
{
Key = grouping.Key;
this.AddRange(grouping);
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="slg">The </param>
/// <returns>Theitems source for a LongListSelector</returns>
private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
{
List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
foreach (string key in slg.GroupDisplayNames)
{
if (key == "...")
{
list.Add(new AlphaKeyGroup<T>(GlobeGroupKey));
}
else
{
list.Add(new AlphaKeyGroup<T>(key));
}
}
return list;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="items">The items to place in the groups.</param>
/// <param name="ci">The CultureInfo to group and sort by.</param>
/// <param name="getKey">A delegate to get the key from an item.</param>
/// <param name="sort">Will sort the data if true.</param>
/// <returns>An items source for a LongListSelector</returns>
public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
{
SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
List<AlphaKeyGroup<T>> list = CreateGroups(slg);
foreach (T item in items)
{
int index = 0;
if (slg.SupportsPhonetics)
{
//check if your database has yomi string for item
//if it does not, then do you want to generate Yomi or ask the user for this item.
//index = slg.GetGroupIndex(getKey(Yomiof(item)));
}
else
{
index = slg.GetGroupIndex(getKey(item));
}
if (index >= 0 && index < list.Count)
{
list[index].Add(item);
}
}
if (sort)
{
foreach (AlphaKeyGroup<T> group in list)
{
group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
}
}
return list;
}
}
The FilmatesInGroup.cs and FilmatesByName.cs is the same as PeopleInGroup.cs and PeopleByFirstName.cs in the PhoneToolKit example with the names adapted.
The longlistFilmates LongListSelector Object is inserted directly inside the PivotItem no.3 ( no Grid and no ScrollView )
Thanks in advance for any help!

C# get nesting Level of Tree

Let´s say I have two classes:
public Foo
{
public List<Foo> Childs { get; set; }
public Bar BarObj { get; set; }
public int Level { get; set; }
}
public Bar
{
public List<Foo> Childs { get; set; }
}
Now I want to get the nesting-level from a Collection of "Foo" Objects
my current working Method looks like this:
int currentLevel = 0;
public void ApplyNestingLevel(List<Foo> list)
{
foreach(var item in list)
{
item.Level = currentLevel;
if(item.Childs.Count > 0 || item.BarObj.Childs.Count > 0)
{
currentLevel++;
}
ApplyNestingLevel(item.Childs);
ApplyNestingLevel(item.BarObj.Childs);
}
}
how could I make this more "elegant/simple" ?
public void ApplyNestingLevel(Foo f)
{
ApplyNestingLevel(f, 0);
}
public void ApplyNestingLevel(Foo f, int level)
{
if(f == null) { return; }
f.Level = level
if(f.Childs != null) {
foreach(Foo child in f.Childs)
{
ApplyNestingLevel(child, level + 1);
}
}
if(f.BarObj != null && f.BarObj.Childs != null) {
foreach(Foo child in f.BarObj.Childs)
{
ApplyNestingLevel(child, level + 1);
}
}
}
Store a reference to the parent and make the Level property recursive.
I added an example and a couple other design suggestions in the code sample below. Hope this helps. FYI, this is pretty much straight out of the Gang of Four's design for the Composite Pattern, which should be required reading for anyone who is serious about OOP.
DoFactory .NET Composite Pattern
Design Patterns: Elements of Reusable Object-Oriented Software, on Amazon.com
public class Foo
{
public Foo(Foo parent = default(Foo))
{
this.parent = parent;
this.children = new List<Foo>();
}
private readonly Foo parent;
private readonly List<Foo> children;
public int Level { get { return ReferenceEquals(parent,null) ? 0 : parent.Level + 1; } }
// don't expose the actual list... see below for why
public IEnumerable<Foo> Children { get { foreach(Foo child in this.children) yield return child; } }
// instead of exposing the child object list
// declare an explicit method with any parameters
// necessary. this allows you to enforce the invariant
// condition that all objects in a children collection
// will have their parent reference set to their
// actual parent
public void AddChild()
{
Foo newChild = new Foo(parent:this);
this.children.Add(newChild);
}
// if you need the ability to remove items as well,
// you can expose a remove method too. Just make
// sure that you validate expected preconditions
public int RemoveChild(Foo childToRemove)
{
if(ReferenceEquals(childToRemove,null)) throw new ArgumentNullException("childToRemove");
if(!ReferenceEquals(this,childToRemove.parent)) throw new ArgumentException("The object cannot be removed because the current object is not the correct parent.","childToRemove");
return children.RemoveAll((Foo existentChild) => existentChild.Equals(childToRemove));
}
}
my version, i using extensions.
public static class EnumerableExtensions
{
/// <summary>Get max nesting level.</summary>
/// <param name="source">Source.</param>
/// <param name="children">Selector.</param>
/// <typeparam name="T">Type.</typeparam>
/// <returns><see cref="IEnumerable{T}"/>.</returns>
public static int GetMaxNestingLevel<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> children)
{
return source.SelectMany(x => GetNestingLevel(x, 0)).Max();
IEnumerable<int> GetNestingLevel(T source, int level)
{
if (children(source) != null)
{
return children(source).SelectMany(x => GetNestingLevel(x, level + 1));
}
else
{
return new List<int> { level }
}
}
}
}
than u can use it like
var max = Foo.Childs.GetMaxNestingLevel(x => x.Childs);
ps
mayby you net tests (NUnit)
using NUnit.Framework;
....
public class EnumerableExtensionsTests
{
private static IEnumerable GetMaxNestingLevelTestCases
{
get
{
yield return new TestCaseData(new int[] { 1, 2, 3, 4 }).Returns(4);
yield return new TestCaseData(new int[] { 4, 3, 2, 1 }).Returns(4);
yield return new TestCaseData(new int[] { 1, 10, 0, 1 }).Returns(10);
yield return new TestCaseData(new int[] { 1, 1, 1, 1 }).Returns(1);
yield return new TestCaseData(new int[] { 1, 1, 1, 2 }).Returns(2);
}
}
[TestCaseSource(nameof(GetMaxNestingLevelTestCases))]
public int GetMaxNestingLevelTest(ICollection<int> sourceNestingLevel)
{
var testSource = sourceNestingLevel.Select(x => new NestingLevelTestClass(x)).ToList();
return testSource.GetMaxNestingLevel(x => x.Children);
}
private class NestingLevelTestClass
{
public NestingLevelTestClass(int childrenLevel = 0)
{
if (childrenLevel != 0)
{
Children = new List<NestingLevelTestClass>
{
new NestingLevelTestClass(childrenLevel - 1),
};
}
}
public ICollection<NestingLevelTestClass> Children { get; set; }
}
}

How to check for common objects between 2 generic lists

I have 2 lists that I need to check for common objects that are being passed to a generic wrapper.
The first list (selList) is a typed entity list. The ID field in this list is different, based on what the base type for the list being created.
The second list (masterList) is an anonymous IList that I know has 2 properties {ID, DESC} - ID (could be int or string), and description (string). I can get the value of the ID property in this list.
I would like to return an extension of the master list that has a boolean field indicating whether the item in the master list is contained in the selList.
I'm thinking that I'm somewhere along the lines of the Visitor pattern.
public class SelectionCriteria<T> : where T : class
{
public IList<T> EligibleList { get; private set; }
public IList LookupList { get; private set; }
}
LookupList = new List<object>
{
new { ID = "fid", DESC = "Record 1"},
new { ID = "Record2", DESC = "Record 2"},
new { ID = "Record3", DESC = "Record 3"},
new { ID = "Record4", DESC = "Record 4"},
};
EligibleList = new List<AssetClass>
{
new AssetClass { FEE_ID = "fid", ASSET_CLASS = "A" },
};
I should get the following results:
LookupList[0] == true
LookupList[1] == false
LookupList[2] == false
LookupList[3] == false
Is there a better way to solve this problem?
var results = LookupList.Select(l => EligibleList.Any(e => e.FEE_ID==l.ID))
.ToList();
Using this as a definition for SelectionCriteria<T>
public class SelectionCriteria<T>
where T : class
{
public IList<T> EligibleList { get; private set; }
public IList LookupList { get; private set; }
public SelectionCriteria(IList lookupList, IList<T> eligibleList)
{
LookupList = lookupList;
EligibleList = eligibleList;
}
public bool this[int index]
{
get
{
var element = LookupList[index];
foreach (var item in EligibleList)
{
if (item.Equals(element))
{
return true;
}
}
return false;
}
}
}
And this as a definition for AssetClass
public class AssetClass : IEquatable<AssetClass>
{
public string FEE_ID { get; set; }
public string ASSET_CLASS { get; set; }
public bool Equals(AssetClass other)
{
return !ReferenceEquals(other, null) && other.FEE_ID == FEE_ID && other.ASSET_CLASS == ASSET_CLASS;
}
//Check to see if obj is a value-equal instance of AssetClass, if it's not, proceed
// to doing some reflection checks to determine value-equality
public override bool Equals(object obj)
{
return Equals(obj as AssetClass) || PerformReflectionEqualityCheck(obj);
}
//Here's where we inspect whatever other thing we're comparing against
private bool PerformReflectionEqualityCheck(object o)
{
//If the other thing is null, there's nothing more to do, it's not equal
if (ReferenceEquals(o, null))
{
return false;
}
//Get the type of whatever we got passed
var oType = o.GetType();
//Find the ID property on it
var oID = oType.GetProperty("ID");
//Get the value of the property
var oIDValue = oID.GetValue(o, null);
//If the property type is string (so that it matches the type of FEE_ID on this class
// and the value of the strings are equal, then we're value-equal, otherwise, we're not
return oID.PropertyType == typeof (string) && FEE_ID == (string) oIDValue;
}
}
You can get elements that are found in the list of eligible items that exist in the list of lookup items like so:
for (var i = 0; i < assetClassSelectionCriteria.LookupList.Count; ++i)
{
Console.WriteLine("LookupList[{0}] == {1}", i, assetClassSelectionCriteria[i]);
}
You could also use the following for PerformReflectionEqualityCheck in AssetClass if you don't like seeing the reflection goodness
private bool PerformReflectionEqualityCheck(object o)
{
if (ReferenceEquals(o, null))
{
return false;
}
dynamic d = o;
try
{
return FEE_ID == (string) d.ID;
}
catch
{
return false;
}
}
If by "extension of the master list" you meant an extension method, then, instead of declaring an indexer on SelectionCriteria<T> to get the results, you could do something like this:
public static class SelectionCriteriaExtensions
{
public static bool IsLookupItemEligible<T>(this SelectionCriteria<T> set, int index)
where T : class
{
var element = set.LookupList[index];
foreach (var item in set.EligibleList)
{
if (item.Equals(element))
{
return true;
}
}
return false;
}
}
and call it like this:
assetClassSelectionCriteria.IsLookupItemEligible(0);

How to change Replace an Object's Variable using Session in ASP.NET C#

I am trying to figure out how I can change up an order by the customer over a web browser. The customer will order an item with product Id (key), the name of product, the price of the product, and the quantity he wants. I would like to know how I can change his order by replacing the OLD item with the old quantity with the same item with a different quanitity SO basically clicking to choose the item and placing 2 different quantities he wishes to purchase. The shopping cart holds the Items that are purchased, so I was wondering how I could destroy an OrderItem from the shopping cart then recreate it.
When my code find the key that is already in the shopping cart, then It needs to be destroyed and recreated with a new Quanitity (a text box from the web app).
protected void btnOrder_Click(object sender, EventArgs e)
{
//Check for Shoppingcart object
// Create first if not there
if (Session["cart"] == null)
Session["cart"] = new ShoppingCart();
int quantity = 0;
// make sure there is text
if (txtQuantity.Text.Trim().Length != 0)
{
quantity = int.Parse(txtQuantity.Text);
if (((ShoppingCart)Session["cart"]).
keyExists(int.Parse(productID.Text)))
{
//Here I should Destroy the current item that exists and replace with new one
}
else // This is a new item
{
// Make the item
OrderItem item = new OrderItem(
int.Parse(productID.Text), productName.Text,
double.Parse(productPrice.Text),
int.Parse(txtQuantity.Text));
// add to cart
((ShoppingCart)Session["cart"]).addToCart(item);
}
// How does this work? Who is sender?
this.btnReturn_Click(sender, e);
}
else
{
Response.Write("Nothing Ordered<br>You must order some of the product or return to the Catalog");
}
Here is the OrderItem object
public class OrderItem
{
private int productID;
private string prodName;
private double unitPrice;
private int quantityOrdered;
private string exceptionStr;
public OrderItem(int id, string name, double price, int quantity)
{
prodName = name;
exceptionStr = "Numeric data must not be negative";
if ( id < 0 || price < 0 || quantity < 0)
{
throw new System.ArgumentException(exceptionStr);
}
else
{
productID = id;
unitPrice = price;
quantityOrdered = quantity;
}
}
#region Public Properties
public int ProductID
{
get
{
return productID;
}
}
public string ProductName
{
get
{
return prodName;
}
}
public double UnitPrice
{
get
{
return unitPrice;
}
}
public int QuantityOrdered
{
get
{
return quantityOrdered;
}
set
{
if( value < 0 )
{
throw new ArgumentException(exceptionStr);
}
else
{
quantityOrdered = value;
}
}
}
#endregion
}
Here is the Shoppingcart for your viewing:
public class ShoppingCart : IEnumerable
{
private SortedList theCart;
public ShoppingCart() {
theCart = new SortedList();
} // end of Constructor
public bool HasItems {
get{
bool hasItems = false;
if( theCart.Count > 0 )
hasItems = true;
return hasItems;
}
set {
// ignore this is read only
}
} // end of HasItems
public void addToCart(OrderItem item) {
theCart.Add(item.ProductID, item);
}// AddToCaArt
/// <summary>
/// deletes item that is passed
/// </summary>
/// <param name="item"></param>
public void deleteFromCart(OrderItem item)
{
theCart.Remove(item.ProductID);
} // end deleteFromCart
/// <summary>
/// deletes the item with this id key
/// </summary>
/// <param name="id"></param>
public void deleteFromCart(int id)
{
theCart.Remove(id);
} // end deleteFromCart
public OrderItem[] getCartContents()
{
// need to create stuff
OrderItem[] stuff = null;
theCart.Values.CopyTo(stuff, 0);
return (stuff);
} // end getCartContents
public bool keyExists(int ID) {
return theCart.ContainsKey(ID);
}// end keyExists
public ICollection Values
{
get
{
return theCart.Values;
}
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return theCart.GetEnumerator();
}
#endregion
}
I would highly recommend thinking about from a class or model level how a shopping cart would look. I think a set of classes like the following would help a great deal (not the best but an ok design from scratch):
[Serializable]
public class ShoppingCartItem
{
public ShoppingCartItem(guid key, decimal price, int quantity)
{
this.Key = key;
this.Price = price;
this.Quantity = quantity;
}
public Guid Key { get; private set; }
public Decimal Price { get; private set; }
public int Quantity { get; set; }
}
[Serializable]
public class ShoppingCart
{
public ShoppingCart()
{
this.Clear();
}
public ICollection<ShoppingCartItem> Items { get; private set; }
public int ItemCount
{
get { return this.Items.Sum(i => i.Quantity); }
}
public decimal Subtotal
{
get { return this.Items.Sum(i => i.Quantity * i.Price); }
}
public void Clear()
{
this.Items = new List<ShoppingCartItem>();
}
}
Now the ShoppingCart is serializable for the ability to be stored in ASP.Net session (or making a wish list :))
Now I'm not a fan of the loosely typed ASP.Net session so I borrowed, from some where I can't remember, this fantastic class to make strongly typed Session objects:
using System;
using System.Web;
namespace Company.Product.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance == null)
{
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key] =
instance = new T();
}
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
To use it for this example I would then create:
public class ShoppingCartSession : SessionBase<ShoppingCart> { }
Then I can use it anywhere in my code:
var item = ShoppingCartSession.Current.Items.FirstOrDefault(i => i.Key= key);
if (item == null)
{
ShoppingCartSession.Current.Items.Add(
new ShoppingCartItem(Key, price, quantity));
}
else
{
item.Quantity = item.Quantity + quantity;
}
Strongly typed session shopping cart object that is extensible and allows you to do what you'd want and more. It can also be accessed by other parts of your application to show the number of items in the cart and a subtotal for an area, say at the top of your application to show a small preview of the shopping cart status.
In your ShoppingCart class, you could add a method called IncreaseQuantity(int productID) (and a DecreaseQuantity method).
public void IncreaseQuantity(int productID)
{
int indexOfProduct = theCart.IndexOfKey(productID);
if(indexOfProduct != -1)
{
this.theCart[indexOfProduct].quantityOrdered++;
}
}
Then call the method from your session
ShoppingCart cart = (ShoppingCart)Session["cart"];
if (cart.keyExists(int.Parse(productID.Text)))
{
//can store the parsed int in a variable instead to prevent...
//having to parse twice.
cart.IncreaseQuantity(int.Parse(productID.Text));
}
I think there is no way.
What is it that is bothering you with needing to recreate the object?
Is it performance, or keeping the code clean?
If it is a performance issue:
Consider saving a separate object on the Session for each item, like so -
int itemID = int.Parse(productID.Text);
int productQuantity = Session["item_number_" + itemID];
If it a an issue of keeping your code clean:
Consider putting all the Session logic in a property:
public ShoppingCart SessionCart
{
get
{
if (Session["cart"] == null)
return new ShoppingCart();
else
return (ShoppingCart)Session["cart"];
}
set
{
Session["cart"] = value;
}
}
Well one way is to maintain quantity as part of every OrderItem and then perhaps get the total count of shopping car by enumerating each individual OrderItem quantity. But then each OrderItem ID must be present only once ShoppingCart.
For example, add a method in ShoppingCart like
public OrderItem Retrieve(int id)
{
return theCart[id] as OrderItem;
}
And then if cart contains same product id already
OrderItem orderItem = cart.Retrieve(1);
item.QuantityOrdered += 1;
Finally assign the updated cart object to Session variable.
Another way to achieve is adding another OrderItem in ShoppingCart and maintaining count grouped by OrderItem Id

Best approach find position of an item in Lucene search results

I am using Lucene.NET and able to search get hit results as ScoreDoc[].
I need to know specific item position in ScoreDoc[]. All items in ScoreDoc[] are unique.
Sample code:
luceneSearcher.Search(query, collector);
ScoreDoc[] scores = collector.TopDocs().scoreDocs
For example, I need to get find item position in ScoreDoc[], which has custom ID property where value could be '99999'.
I can iterate through item in scores[] and check for ID property which matches '99999' then return the position, but this can have performance hit because scores[] can have thousands of items.
Is there any better technique?
Thanks
I came up with creating new ExtendedCollector which stores CollectedDocuments.
public class ExtendedCollector : Collector
{
private Scorer _scorer;
private Int32 _docBase;
private List<CollectedDocument> _documents;
public ExtendedCollector()
{
_documents = new List<CollectedDocument>();
}
public override void SetScorer(Scorer scorer)
{
_scorer = scorer;
}
public override void Collect(int doc)
{
var docId = _docBase + doc;
var score = _scorer.Score();
var currentDoc = _documents.FirstOrDefault(d => d.DocId == docId);
if (currentDoc == null)
_documents.Add(new CollectedDocument()
{DocId = docId, Score = score, OriginalIndex = _documents.Count, Index = _documents.Count});
else
currentDoc.Score = score;
}
public override void SetNextReader(IndexReader reader, int docBase)
{
_docBase = docBase;
}
public override bool AcceptsDocsOutOfOrder()
{
return false;
}
public List<CollectedDocument> Documents
{
get { return _documents; }
}
public List<CollectedDocument> DocumentsByScore
{
get
{
var result = _documents.OrderByDescending(d => d.Score).ToList();
var itemId = 0;
foreach (var collectedDocument in result)
{
itemId++;
collectedDocument.Index = itemId;
}
return result;
}
}
}
CollectedDocument looks like this
public class CollectedDocument
{
public Int32 DocId { get; set; }
public float Score { get; set; }
public int OriginalIndex { get; set; }
public int Index { get; set; }
}
Whenever you want to get results you would do
var myCollector = new ExtendedCollector();
searcher.Search(searchQuery, myCollector);
foreach (var doc in myCollector.Documents)
{
var docIndex = doc.Index; //this is the current index in a list
var originalIndex = doc.OriginalIndex; //this is item Id set when doc was collected
}
You can also get the documents ordered by score using
myCollector.DocumentsByScore
This might not be the easiest solution, but it works. If anyone has a better solution, please post it as I'd like to know that as well.

Categories

Resources