I need a data structure like Queue. Only the first element can exit and new elements should be added to end of Queue. And also I need to access to last element.
The System.Collections.Queue has all functionality I need except the last one.
I wondering is there any built in data structure like this?
The C# LinkedList class is exactly what you need.
See https://stackoverflow.com/a/1798358/2394945
Based on comments and other answers the best way is create my own Queue, but implementing a Queue with best performance is a duplicate(because it already exists in c#).
So I simply create a MyQueue class and use a System.Collections.Generic.Queue<T> as its inner data structure. here is the code:
/// <summary>
/// A generic first in first out data structure with access to last element.
/// </summary>
/// <typeparam name="T">The specific data type for this queue.</typeparam>
public class MyQueue<T>
{
#region Varibles
private Queue<T> _inner;
private T _last;
#endregion
#region Properties
/// <summary>
/// Number of elements of this Queue.
/// </summary>
public int Count
{
get
{
return _inner.Count;
}
}
/// <summary>
/// The inner Queue in this structure.
/// </summary>
public Queue<T> Inner
{
get
{
return _inner;
}
}
#endregion
public MyQueue()
{
_inner = new Queue<T>();
}
#region Methods
/// <summary>
/// Adds an object to the end of the queue.
/// </summary>
/// <param name="item">Specific item for add.</param>
public void Enqueue(T item)
{
_inner.Enqueue(item);
_last = item;
}
/// <summary>
/// Return and removes the first item in the queue.
/// </summary>
/// <returns>The first item in queue.</returns>
/// <exception cref="InvalidOperationException">InvalidOperationException</exception>
public T Dequeue()
{
if (_inner.Count > 0)
return _inner.Dequeue();
else
throw new InvalidOperationException("The Queue is empty.");
}
/// <summary>
/// Returns the first item in the queue without removing it.
/// </summary>
/// <returns>The first item in the queue.</returns>
public T Peek()
{
return _inner.Peek();
}
/// <summary>
/// Returns the last item in the queue without removing it.
/// </summary>
/// <returns>The last item in the queue.</returns>
public T Last()
{
return _last;
}
/// <summary>
/// Clears all items in the queue.
/// </summary>
public void Clear()
{
_inner.Clear();
}
#endregion
}
Related
Currently, I'm creating custom MVC Html Helpers which I will be using through a fluent API.
To give an example to understand it, I'll have the following helper which is (or should be in a not too distant future) generate a grid:
#(Html.GridFor(Model)
.WithName("MyName")
.WithColumns(model =>
{
model.Bind(x => x.Name);
model.Bind(x => x.DateCreated);
model.Bind(x => x.DateUpdated);
}).Render());
Now, everything is constructed with the start point. The IGridBuilder.
/// <summary>
/// When implemented by a class, it defines the class as an object that can construct a grid by using a fluent API.
/// </summary>
public interface IGridBuilder<TModel> : IHtmlHelper, IDataSource<TModel>
{
#region Properties
/// <summary>
/// Gets the name of the <see cref="IGridBuilder{TModel}" />.
/// </summary>
string Name { get; }
#endregion
#region Methods
/// <summary>
/// Sets the name of the <see cref="IGridBuilder{TModel}" />. This name will be used as an id on the outer element that
/// holds the entire grid.
/// </summary>
/// <param name="name">The name that the <see cref="IGridBuilder{TModel}" /> should have.</param>
/// <returns>An <see cref="IGridBuilder{TModel}" /> that can be used to construct the grid through a fluent API.</returns>
IGridBuilder<TModel> WithName(string name);
/// <summary>
/// Set the columns of the model that should be bound to grid.
/// </summary>
/// <param name="bindAllColumns">The action that will bind all the columns.</param>
/// <returns>An <see cref="IGridBuilder{TModel}" /> that is used to construct the grid.</returns>
IGridBuilder<TModel> WithColumns(Action<IColumnBinder<TModel>> bindAllColumns);
/// <summary>
/// Renders the grid with all the set properties.
/// </summary>
/// <returns>A <see cref="MvcHtmlString" /> that contains the HTML representation of the grid.</returns>
MvcHtmlString Render();
#endregion
}
and to make the bind commands, I'm using an IColumnBinder interface:
/// <summary>
/// When implemented by a class, this class is marked as being an builder that can construct a column through a fluent API.
/// </summary>
/// <typeparam name="TModel"></typeparam>
public interface IColumnBinder<TModel> : IHtmlHelper, IDataSource<TModel>
{
#region Methods
/// <summary>
/// Binds an column to the grid.
/// </summary>
/// <typeparam name="TItem">The type of the column on which to bind the items.</typeparam>
/// <param name="propertySelector">The functional that will bind the control to the grid.</param>
void Bind<TItem>(Expression<Func<TModel, TItem>> propertySelector);
/// <summary>
/// Apply a specific css class on an element.
/// </summary>
/// <param name="className">The name of the css class that should be placed on the element.</param>
/// <returns>As <see cref="IColumnBinder{TModel}"/> that is used to construct this column through a fluent API.</returns>
IColumnBinder<TModel> WithCss(string className);
#endregion
}
Now, what's the best approach to link an IColumnBuilder to an IGridBuilder?
To make it very short, I'm struggling with the following:
The IColumnBuilder set ups specific properties but the rendering takes place in the IGridBuilder interface.
The main problem lies in the following code:
/// <summary>
/// Set the columns of the model that should be bound to grid.
/// </summary>
/// <param name="bindAllColumns">The action that will bind all the columns.</param>
/// <returns>An <see cref="IGridBuilder{TModel}" /> that is used to construct the grid.</returns>
public IGridBuilder<TModel> WithColumns(Action<IColumnBinder<TModel>> bindAllColumns)
{
bindAllColumns(new ColumnBinder<TModel>());
return this;
}
So here I execute the action to bind the column:
model.Bind(x => x.Name)
But how can I keep a reference between the IGridBuilder and the IColumnBuilder to construct it in a proper way afterwars?
Or are there other solutions?
Ok,
After hours of searching I've found a solution and therefore I'm answering my own question. However, if there are users that have another approach to the same problem, please tell me so I can adapt me code maybe.
This code will primarly use a class to transfer objects, since a class is a reference type it can be passed to another object, and that object can manipulate the object.
So, I have written a custom HTML helper that should work as the following:
#(Html.GridFor(Model)
.WithName("MyName")
.WithColumns(model =>
{
model.Bind(x => x.Name).WithCss("row first");
model.Bind(x => x.DateCreated);
model.Bind(x => x.DateUpdated);
}).Render());
So, I do have a model that's enumerable and that I will pass to the grid. The grid takes 3 columns of the model and renders the grid.
For this code, I have a couple of interfaces which helps me throughout the process:
An HTML Helper interface (just holds an object to the HtmlHelper):
/// <summary>
/// Provides a way to extend the <see cref="HtmlHelper" /> to construct objects of various kinds.
/// </summary>
public static class HtmlHelperExtensions
{
#region Grid
/// <summary>
/// Constructs a grid for a property that holds a collection.
/// </summary>
/// <typeparam name="TModel">The type of the model on which this grid is being build.</typeparam>
/// <typeparam name="TEntity">The type of a single item in the collection. </typeparam>
/// <param name="htmlHelper">The helper on which this method is executed. </param>
/// <param name="dataSource">The datasource on which the items are bound. </param>
/// <returns>An <see cref="IGridBuilder{TEntity}" /> that is used to construct the grid.</returns>
public static IGridBuilder<TEntity> GridFor<TModel, TEntity>(this HtmlHelper<TModel> htmlHelper,
IEnumerable<TEntity> dataSource)
{
return new GridBuilder<TEntity>(htmlHelper, dataSource);
}
#endregion
}
A Datasource interface (just holds an interface to the datasource):
public interface IDataSource<out TModel>
{
#region Properties
/// <summary>
/// Gets the source that will be bound to the implemented object.
/// </summary>
IEnumerable<TModel> DataSource { get; }
#endregion
}
And then we have all the other code.
The HTML Helper extension class is the first one:
/// <summary>
/// Provides a way to extend the <see cref="HtmlHelper" /> to construct objects of various kinds.
/// </summary>
public static class HtmlHelperExtensions
{
#region Grid
/// <summary>
/// Constructs a grid for a property that holds a collection.
/// </summary>
/// <typeparam name="TModel">The type of the model on which this grid is being build.</typeparam>
/// <typeparam name="TEntity">The type of a single item in the collection.</typeparam>
/// <param name="htmlHelper">The helper on which this method is executed.</param>
/// <param name="dataSource">The datasource on which the items are bound.</param>
/// <returns>An <see cref="IGridBuilder{TEntity}" /> that is used to construct the grid.</returns>
public static IGridBuilder<TEntity> GridFor<TModel, TEntity>(this HtmlHelper<TModel> htmlHelper,
IEnumerable<TEntity> dataSource)
{
return new GridBuilder<TEntity>(htmlHelper, dataSource);
}
#endregion
}
Then the next one is an implementation of the IGridBuilder interface:
/// <summary>
/// Provides an implemention of the <see cref="IGridBuilder{TModel}" /> that is used to construct the grid through a
/// fluent API.
/// </summary>
/// <typeparam name="TModel">The type of the model that the grid will hold.</typeparam>
public class GridBuilder<TModel> : IGridBuilder<TModel>
{
#region Constructors
/// <summary>
/// Creates a new instance of the <see cref="GridBuilder{TModel}" />.
/// </summary>
/// <param name="helper">The <see cref="HtmlHelper" /> that is used to construct the grid.</param>
/// <param name="dataSource">The collection of objects that will be bound to the grid.</param>
public GridBuilder(HtmlHelper helper, IEnumerable<TModel> dataSource)
{
htmlHelper = helper;
DataSource = dataSource;
Constructor = new GridConstructor<TModel>(htmlHelper, DataSource);
}
#endregion
#region IGridBuilder Members
/// <summary>
/// Gets the name of the <see cref="IGridBuilder{TModel}" />.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets the constructor that will be used to construct this <see cref="IGridBuilder{TModel}" />.
/// </summary>
public IGridContructor<TModel> Constructor { get; set; }
/// <summary>
/// Gets the source that will be bound to the implemented object.
/// </summary>
public IEnumerable<TModel> DataSource { get; private set; }
/// <summary>
/// Gets the <see cref="HtmlHelper" /> object.
/// </summary>
public HtmlHelper htmlHelper { get; private set; }
/// <summary>
/// Sets the name of the <see cref="IGridBuilder{TModel}" />. This name will be used as an id on the outer element that
/// holds the entire grid.
/// </summary>
/// <param name="name">The name that the <see cref="IGridBuilder{TModel}" /> should have.</param>
/// <returns>An <see cref="IGridBuilder{TModel}" /> that can be used to construct the grid through a fluent API.</returns>
public IGridBuilder<TModel> WithName(string name)
{
Name = name;
return this;
}
/// <summary>
/// Set the columns of the model that should be bound to grid.
/// </summary>
/// <param name="bindAllColumns">The action that will bind all the columns.</param>
/// <returns>An <see cref="IGridBuilder{TModel}" /> that is used to construct the grid.</returns>
public IGridBuilder<TModel> WithColumns(Action<IColumnBinder<TModel>> bindAllColumns)
{
var columnBinder = new ColumnBinder<TModel>(Constructor);
bindAllColumns(columnBinder);
return this;
}
/// <summary>
/// Renders the grid with all the set properties.
/// </summary>
/// <returns>A <see cref="MvcHtmlString" /> that contains the HTML representation of the grid.</returns>
public MvcHtmlString Render()
{
var outputBuilder = new StringBuilder();
BaseElementBuilder parentElement = DivFactory.DivElement().WithCss("header");
outputBuilder.Append(parentElement.ToString(TagRenderMode.StartTag));
outputBuilder.Append(parentElement.ToString(TagRenderMode.EndTag));
return new MvcHtmlString(outputBuilder.ToString());
}
#endregion
}
Then an implementation of the IGridColumnBinder:
/// <summary>
/// Provides an implementation of the <see cref="IColumnBinder{TModel}" /> that can be used to construct a column
/// through a fluent API.
/// </summary>
/// <typeparam name="TModel">The type of the datasource that's bound to the grid.</typeparam>
public class ColumnBinder<TModel> : IColumnBinder<TModel>
{
#region Constructors
/// <summary>
/// Creates a new instance of the <see cref="ColumnBinder{TModel}" />.
/// </summary>
/// <param name="constructor">An <see cref="IGridContructor{TModel}" /> that contains the builder to construct the grid.</param>
public ColumnBinder(IGridContructor<TModel> constructor)
{
Constructor = constructor;
}
#endregion
#region IColumnBinder Members
/// <summary>
/// Gets the values that are bound to this <see cref="IColumnBinder{TModel}" />.
/// </summary>
public IGridContructor<TModel> Constructor { get; private set; }
/// <summary>
/// Gets the css class of the <see cref="IColumnBinder{TModel}" />.
/// </summary>
public string CssClass { get; private set; }
/// <summary>
/// Gets the values that are bound to this <see cref="IColumnBinder{TModel}" />.
/// </summary>
public IList<object> Values { get; set; }
/// <summary>
/// Binds an column to the grid.
/// </summary>
/// <typeparam name="TItem">The type of the column on which to bind the items.</typeparam>
/// <param name="propertySelector">The functional that will bind the control to the grid.</param>
/// <returns>As <see cref="IColumnBinder{TModel}" /> that is used to construct this column through a fluent API.</returns>
public IColumnBinder<TModel> Bind<TItem>(Expression<Func<TModel, TItem>> propertySelector)
{
string name = ExpressionHelper.GetExpressionText(propertySelector);
name = Constructor.htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForProperty(() => default(TModel),
typeof (TModel), name);
// Get's the name to display on the column in grid. The Display attribute is used if present, otherwise the name of the property is used.
string displayName = string.IsNullOrEmpty(metadata.DisplayName)
? metadata.PropertyName
: metadata.DisplayName;
Values =
Constructor.DataSource.Select(myVar => propertySelector.Compile()(myVar))
.Select(dummy => (object) dummy)
.ToList();
Constructor.builderProperties.Add(displayName, this);
return this;
}
/// <summary>
/// Apply a specific css class on an element.
/// </summary>
/// <param name="className">The name of the css class that should be placed on the element.</param>
/// <returns>As <see cref="IColumnBinder{TModel}" /> that is used to construct this column through a fluent API.</returns>
public IColumnBinder<TModel> WithCss(string className)
{
CssClass = className;
return this;
}
#endregion
}
And as last the implementation of the IGridConstructor.
/// <summary>
/// Provides an implemention of the <see cref="IGridContructor{TModel}" /> that is used to construct the grid through a
/// fluent API.
/// </summary>
/// <typeparam name="TModel">The type of the model that the grid will hold.</typeparam>
public class GridConstructor<TModel> : IGridContructor<TModel>
{
#region Constructors
/// <summary>
/// Creates a new instance of the <see cref="GridConstructor{TModel}" />.
/// </summary>
/// <param name="helper">The <see cref="HtmlHelper" /> that is used to built the model.</param>
/// <param name="source">The model that is bound to the grid.</param>
public GridConstructor(HtmlHelper helper, IEnumerable<TModel> source)
{
htmlHelper = helper;
DataSource = source;
builderProperties = new Dictionary<string, IColumnBinder<TModel>>();
}
#endregion
#region Properties
/// <summary>
/// Provides a dictionary that contains all the properties for the builder.
/// </summary>
public IDictionary<string, IColumnBinder<TModel>> builderProperties { get; set; }
/// <summary>
/// Gets the source that will be bound to the implemented object.
/// </summary>
public IEnumerable<TModel> DataSource { get; private set; }
/// <summary>
/// Gets the <see cref="HtmlHelper" /> object.
/// </summary>
public HtmlHelper htmlHelper { get; private set; }
#endregion
}
Now, how does this works exactely?
The HtmlHelper returns an member that implements an IGridBuilder, so in the example above, it returns a GridBuilder.
On that GridBuilder, there are a couple of elements that you can call, and one more important is the WithColumns method that takes a IColumnBinder action and there's the trick. The implementation of IColumnBinder takes a reference to an IGridConstructor. And it's that constructor that will be fully built up.
So all the things we need to know for rendering, including each css class for a given column are exposed through the GridBuilder.GridContructor
So, a very vert long post, but I hope it helps some people.
I need to make a ConcurrentBag as notifable. I need to know that is it safe? Code for the class is
public class NotifiableConcurrentBag<T> : ConcurrentBag<T>, INotifyCollectionChanged where T : class
{
public NotifiableConcurrentBag()
{
dispatcher = Dispatcher.CurrentDispatcher;
}
private Dispatcher dispatcher;
public event NotifyCollectionChangedEventHandler CollectionChanged;
public new void Add(T item)
{
base.Add(item);
if (CollectionChanged != null)
{
if (Thread.CurrentThread == dispatcher.Thread)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
else
dispatcher.BeginInvoke((Action)(() =>
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
));
}
}
}
Thanks in advance.
You're using method hiding: public new void Add(T item) { ... }. So, when the client code gets the reference to the instance of NotifiableConcurrentBag<T> as ConcurrentBag<T> the wrong version of Add() (for ConcurrentBag<T>) method will be called.
I would like to suggest you extracting the IConcurrentBag<T> interface.
public interface IConcurrentBag<T> : IProducerConsumerCollection<T>
{
void Add(T item);
bool TryPeek(out T result);
bool IsEmpty { get; }
}
Then introduce new extended interface INotifiableConcurrentBag<T> which actually supports INotifyCollectionChanged interface:
public interface INotifiableConcurrentBag<T> : IConcurrentBag<T>, INotifyCollectionChanged
{
}
After that just implement NotifiableConcurrentBag<T> class (prefer composition over inheritance). Insert the notification logic instead of TODO markers.
public class NotifiableConcurrentBag<T> : INotifiableConcurrentBag<T>
{
private readonly ConcurrentBag<T> _concurrentBag;
public NotifiableConcurrentBag()
{
_concurrentBag = new ConcurrentBag<T>();
}
public NotifiableConcurrentBag(IEnumerable<T> collection)
{
_concurrentBag = new ConcurrentBag<T>(collection);
}
#region Implementation of IEnumerable
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
lock (((ICollection)this).SyncRoot)
{
return ((IEnumerable)_concurrentBag).GetEnumerator();
}
}
#endregion
#region Implementation of IEnumerable<T>
/// <summary>
/// Returns an enumerator that iterates through the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </summary>
/// <returns>
/// An enumerator for the contents of the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
lock (((ICollection)this).SyncRoot)
{
return ((IEnumerable<T>)_concurrentBag).GetEnumerator();
}
}
#endregion
#region Implementation of ICollection
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing. </param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins. </param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero. </exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.-or-The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception><filterpriority>2</filterpriority>
void ICollection.CopyTo(Array array, int index)
{
lock (((ICollection)this).SyncRoot)
{
((ICollection)_concurrentBag).CopyTo(array, index);
}
}
/// <summary>
/// Gets the number of elements contained in the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </summary>
/// <returns>
/// The number of elements contained in the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </returns>
int ICollection.Count
{
get
{
lock (((ICollection)this).SyncRoot)
{
return _concurrentBag.Count;
}
}
}
/// <summary>
/// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
/// </summary>
/// <returns>
/// An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
/// </returns>
/// <filterpriority>2</filterpriority>
object ICollection.SyncRoot
{
get { return ((ICollection)_concurrentBag).SyncRoot; }
}
/// <summary>
/// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe).
/// </summary>
/// <returns>
/// true if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe); otherwise, false.
/// </returns>
/// <filterpriority>2</filterpriority>
bool ICollection.IsSynchronized
{
get { return ((ICollection)_concurrentBag).IsSynchronized; }
}
#endregion
#region Implementation of IConcurrentBag<T>
/// <summary>
/// Adds an object to the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </summary>
/// <param name="item">The object to be added to the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>. The value can be a null reference (Nothing in Visual Basic) for reference types.</param>
void IConcurrentBag<T>.Add(T item)
{
lock (((ICollection)this).SyncRoot)
{
_concurrentBag.Add(item);
// TODO: Implement notification!
}
}
/// <summary>
/// Attempts to return an object from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> without removing it.
/// </summary>
/// <returns>
/// true if and object was returned successfully; otherwise, false.
/// </returns>
/// <param name="result">When this method returns, <paramref name="result"/> contains an object from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> or the default value of <paramref name="T"/> if the operation failed.</param>
bool IConcurrentBag<T>.TryPeek(out T result)
{
lock (((ICollection)this).SyncRoot)
{
return _concurrentBag.TryPeek(out result);
}
}
/// <summary>
/// Gets a value that indicates whether the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> is empty.
/// </summary>
/// <returns>
/// true if the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> is empty; otherwise, false.
/// </returns>
bool IConcurrentBag<T>.IsEmpty
{
get
{
lock (((ICollection)this).SyncRoot)
{
return _concurrentBag.IsEmpty;
}
}
}
#endregion
#region Implementation of IProducerConsumerCollection<T>
/// <summary>
/// Attempts to remove and return an object from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </summary>
/// <returns>
/// true if an object was removed successfully; otherwise, false.
/// </returns>
/// <param name="result">When this method returns, <paramref name="result"/> contains the object removed from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> or the default value of <paramref name="T"/> if the bag is empty.</param>
bool IProducerConsumerCollection<T>.TryTake(out T result)
{
lock (((ICollection)this).SyncRoot)
{
bool takeResult = _concurrentBag.TryTake(out result);
if (takeResult)
{
// TODO: Implement notification!
}
return takeResult;
}
}
/// <summary>
/// Copies the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> elements to an existing one-dimensional <see cref="T:System.Array"/>, starting at the specified array index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.</exception><exception cref="T:System.ArgumentException"><paramref name="index"/> is equal to or greater than the length of the <paramref name="array"/> -or- the number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.</exception>
void IProducerConsumerCollection<T>.CopyTo(T[] array, int index)
{
lock (((ICollection)this).SyncRoot)
{
_concurrentBag.CopyTo(array, index);
}
}
/// <summary>
/// Copies the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/> elements to a new array.
/// </summary>
/// <returns>
/// A new array containing a snapshot of elements copied from the <see cref="T:System.Collections.Concurrent.ConcurrentBag`1"/>.
/// </returns>
T[] IProducerConsumerCollection<T>.ToArray()
{
lock (((ICollection)this).SyncRoot)
{
return _concurrentBag.ToArray();
}
}
/// <summary>
/// Attempts to add an object to the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>.
/// </summary>
/// <returns>
/// true if the object was added successfully; otherwise, false.
/// </returns>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>.</param><exception cref="T:System.ArgumentException">The <paramref name="item"/> was invalid for this collection.</exception>
bool IProducerConsumerCollection<T>.TryAdd(T item)
{
lock (((ICollection)this).SyncRoot)
{
bool addResult = ((IProducerConsumerCollection<T>)_concurrentBag).TryAdd(item);
if (addResult)
{
// TODO: Implement notification!
}
return addResult;
}
}
#endregion
#region Implementation of INotifyCollectionChanged
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endregion
}
Basically no, this approach is not safe: thread-safety issues aside (I did not assess its thread-safety), it leaves many possibilities to add items to the collection without actually invoking the notification. Consider the following simpler implementation:
public class NotifiableConcurrentBag<T> : ConcurrentBag<T> where T : class {
public int CountOfAdditions { get; set; }
public new void Add(T item) {
base.Add(item);
Console.WriteLine("Overloaded!");
CountOfAdditions++;
}
}
Now someone writes a tricky code that uses this collection not only as a NotifiableConcurrentBag, but also as simply ConcurrentBag (inherited) and, even worse, IProducerConsumerCollection (implemented through inherited ConcurrentBag):
NotifiableConcurrentBag<string> s = new NotifiableConcurrentBag<string>();
Console.WriteLine("CHANGE --->");
s.Add("s");
ConcurrentBag<string> o = (ConcurrentBag<string>) s;
Console.WriteLine("CHANGE --->");
o.Add("s");
IProducerConsumerCollection<string> col = (IProducerConsumerCollection<string>) s;
Console.WriteLine("CHANGE --->");
col.TryAdd("s");
Console.WriteLine("Overloaded called {0} times", s.CountOfAdditions);
Console.WriteLine("In fact collection has {0} items", s.Count);
The output of this program is the following:
CHANGE --->
Overloaded!
CHANGE --->
CHANGE --->
Overloaded called 1 times
In fact collection has 3 items
This means that your implementation would have left two additions without any notifications. For the implementation to be genuinely safe, you would probably need to wrap the ConcurrentBag rather than inherit it, and implement the interfaces that you need in such a fashion that the notification is always called.
I'm a little bit new to programming in .NET, and there's a little bit of a problem that's truly confusing me.
I am trying to implement the IList<T> interface in one of my classes. I wanted to keep things simple for now, so I simply used the functionality of a declared List<T> field for the methods and added some custom data processing in between.
Most of the methods work well, and the field list gets added to as expected. However, when I try to use the class as a list (e.g. class.ForEach()), it returns a Count of 0. This is despite the internal List<T> having a count of 25.
I'm sure this is really simple, and I apologise if this question is a waste of database space, but it's something that's really holding me back. Can any of you guys help me solve it?
I'll post my current code to show what I'm trying to do:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using ClubEventsData;
using ClubEventsData.Attributes;
using ClubEventsDataHandling.System.Implementations.Conversion;
using Telerik.Sitefinity.DynamicModules.Model;
namespace ClubEventsDataHandling.System.Implementations
{
public class DataRepository<T> : IDataRepository<T> where T : ClubEventData, new()
{
private readonly PropertyDictionaryBasedDynamicConverter<T> _converter;
private readonly IDataHandler _dataHandler;
private readonly List<T> _storageList;
/// <summary>
/// Initializes a new instance of the DataRepository class.
/// </summary>
public DataRepository()
{
_dataHandler = new SitefinityBasedDataHandler<T>();
_converter = new PropertyDictionaryBasedDynamicConverter<T>();
_storageList = new List<T>();
// Populate the data repository.
foreach (DynamicContent dynamicContent in _dataHandler.Get())
{
_storageList.Add(_converter.ConvertToModel(dynamicContent));
}
}
#region Implementation of IEnumerable
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<T> GetEnumerator()
{
return _storageList.GetEnumerator();
}
#endregion
#region Implementation of ICollection<T>
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public void Add(T item)
{
// Create the data item.
T modelItem = CreateDataItem(item);
// Add the item to the list.
_storageList.Add(modelItem);
}
/// <summary>
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
public void Clear()
{
throw new NotImplementedException();
}
/// <summary>
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
/// </summary>
/// <returns>
/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
/// </returns>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
public bool Contains(T item)
{
// Determine if the database contains the item.
return _dataHandler.Get(item.MasterContentID) != null;
}
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
{
_storageList.CopyTo(array, arrayIndex);
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item)
{
// Determine if the master content ID has been set.
ValidateItem(item);
// Delete the item from the database.
_dataHandler.Delete(item.MasterContentID);
// Remove the item from the database.
return _storageList.Remove(item);
}
/// <summary>
/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
public int Count { get; private set; }
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </summary>
/// <returns>
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
/// </returns>
public bool IsReadOnly { get; private set; }
/// <summary>
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
/// </summary>
/// <returns>
/// true if <paramref name="itemID"/>'s item is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
/// </returns>
/// <param name="itemID">The ID of the object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
public bool Contains(Guid itemID)
{
return _dataHandler.Get(itemID) != null;
}
///<summary>Creates the data item in the database and returns the model version of it.</summary>
private T CreateDataItem(T item)
{
// Get the properties of the item.
Dictionary<string, object> propertyDictionary = GetItemProperties(item);
// Create the data representation of the item.
Guid createdItemID = _dataHandler.Create(propertyDictionary);
// Convert a new model item from the dynamic content.
DynamicContent dynamicContent = _dataHandler.Get(createdItemID);
T modelItem = _converter.ConvertToModel(dynamicContent);
return modelItem;
}
///<summary>Gets the properties of the item as a dictionary that is ready to input into data handler methods.</summary>
private static Dictionary<string, object> GetItemProperties(T item)
{
var propertyDictionary = new Dictionary<string, object>();
// Filter the properties according to the mapping attribute.
foreach (PropertyInfo property in item.GetType().GetProperties())
{
// Get the mapping attribute.
object[] customMappingAttributes = property.GetCustomAttributes(typeof (ClubEventDataMappingAttribute), true);
var mappingAttribute = customMappingAttributes[0] as ClubEventDataMappingAttribute;
// Apply the action, depending on the mapping attribute.
if (mappingAttribute != null && mappingAttribute.MappingEnabled)
{
string mappingValue = mappingAttribute.MappingName != null && string.IsNullOrEmpty(mappingAttribute.MappingName) ? property.Name : mappingAttribute.MappingName;
if (mappingValue != null)
{
propertyDictionary.Add(mappingValue, property.GetValue(item, null));
}
}
// Old code, in case didn't work.
/*if ()
{
propertyDictionary.Add(property.Name, property.GetValue(item, null));
}*/
}
return propertyDictionary;
}
/// <summary>
/// Performs validation operations on the item.
/// </summary>
private static void ValidateItem(T item)
{
// Check that the ID is present on the item.
if (item.MasterContentID == Guid.Empty)
{
throw new ContentIDNotSetException("The master content ID was not set for this exception.");
}
}
#endregion
#region Implementation of IList<T>
/// <summary>
/// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
/// </summary>
/// <returns>
/// The index of <paramref name="item"/> if found in the list; otherwise, -1.
/// </returns>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
public int IndexOf(T item)
{
return _storageList.IndexOf(item);
}
/// <summary>
/// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param><param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
public void Insert(int index, T item)
{
// Create a new data item based off the properties of this one.
T modelItem = CreateDataItem(item);
// Insert the model item into the list.
_storageList.Insert(index, modelItem);
}
/// <summary>
/// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the item to remove.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
public void RemoveAt(int index)
{
// Get the item at the index.
T item = this[index];
// Validate the item ID.
ValidateItem(item);
// Delete the item from the database.
_dataHandler.Delete(item.MasterContentID);
// Remove the item from the list.
_storageList.RemoveAt(index);
}
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
/// <returns>
/// The element at the specified index.
/// </returns>
/// <param name="index">The zero-based index of the element to get or set.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.</exception><exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IList`1"/> is read-only.</exception>
public T this[int index]
{
get { return _storageList[index]; }
set
{
// Validate the specified content ID.
ValidateItem(value);
// Update the database instance with the item properties.
_dataHandler.Update(value.MasterContentID, GetItemProperties(value));
// Reflect the changes in the list.
_storageList[index] = value;
}
}
#endregion
#region Implementation of IEnumerable
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}
And here is the method I use to call the repository:
using System.Collections.Generic;
using ClubEventsData;
using System.Linq;
using System;
namespace ClubEventsDataHandling.System.Implementations.Controllers
{
public class TicketDataController : IDataController
{
private DataRepository<Ticket> _repository;
public TicketDataController()
{
_repository = new DataRepository<Ticket>();
}
public List<Ticket> GetDateTickets(Guid dateID)
{
return _repository.Where(ticket => ticket.EventDateBoughtFor.MasterContentID == dateID).ToList();
}
}
}
The reason for _repository.Count being 0 is simply that you don't access your _storageList in the Count property. You need to change it to this:
public int Count
{
get { return _storageList.Count; }
}
I'm currently working on a Windows Forms GUI and I have a Combo that I need to display a list of string values as the DisplayMembers and use a list of user defined enum values as the ValueMember. I'm currently returning a List> from my database access function and I would like to bind this to my Combo box. I've tried assigning the list to the .DataSource property, assigning "Key" to .DataMember and "Value" to .DisplayMember. This is clearly not a valid approach as it is not working.
Can someone please give me another approach that is in good form and actually works?
Thanks
I do use my own class EnumPair<> in combination with two extension methods to bind comboboxes to Properties with enum types.
See if this can help you, that you can work directly with the enums.
Use it like this after implementation:
comboBox.BindToEnumValue<MyEnumType>(myBindingSourceInstance, "PropertyNameOfBindingSource");
That assumes you have a ComboBox named "comboBox" on your form, an Enum called "MyEnumType" and an instance of a BindingSource. The PropertyNameOfBindingSource should be the name of the Property of the type that your BindingSource has a list of, that has the PropertyType of MyEnumType.
Implementation for the background work is found below, the extension methods are not needed, i just do not like write nearly identical lines of code ;-)
public static class ComboBoxExtensions
{
public static void BindToEnumValue<TEnum>(this ComboBox cbo, BindingSource bs, string propertyName)
{
cbo.DataSource = EnumPair<TEnum>.GetValuePairList();
cbo.ValueMember = EnumPair<TEnum>.ValueMember;
cbo.DisplayMember = EnumPair<TEnum>.DisplayMember;
cbo.DataBindings.Add(new Binding("SelectedValue", bs, propertyName));
}
public static void BindClear(this ComboBox cbo)
{
cbo.DataSource = null;
cbo.DataBindings.Clear();
}
}
/// <summary>
/// Represents a <see cref="EnumPair"/> consisting of an value
/// of an enum T and a string represantion of the value.
/// </summary>
/// <remarks>
/// With this generic class every <see cref="Enum"/> can be
/// dynamically enhanced by additional values, such as an empty
/// entry, which is usefull in beeing used with
/// <see cref="ComboBox"/>es.
/// </remarks>
/// <typeparam name="T">The type of the <see cref="Enum"/> to represent.</typeparam>
public partial class EnumPair<T>
{
#region Constants
public const string ValueMember = "EnumValue";
public const string DisplayMember = "EnumStringValue";
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="EnumPair"/> class.
/// </summary>
public EnumPair()
{
Type t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("Class EnumPair<T> can only be instantiated with Enum-Types!");
}
}
/// <summary>
/// Initializes a new instance of the <see cref="EnumPair"/> class.
/// </summary>
/// <param name="value">The value of the enum.</param>
/// <param name="stringValue">The <see cref="string"/> value of the enum.</param>
public EnumPair(T value, string stringValue)
{
Type t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("Class EnumPair<T> can only be instantiated with Enum-Types!");
}
this.EnumValue = value;
this.EnumStringValue = stringValue;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the value part of the <see cref="EnumPair"/>.
/// </summary>
public T EnumValue { get; set; }
/// <summary>
/// Gets or sets the string value of the <see cref="EnumPair"/>.
/// </summary>
public string EnumStringValue { get; set; }
#endregion
#region Methods
/// <summary>
/// Returns a <see cref="string"/> that represents the current <see cref="EnumPair"/>.
/// </summary>
public override string ToString()
{
return this.EnumStringValue;
}
/// <summary>
/// Generates a <see cref="List<T>"/> of the values
/// of the <see cref="Enum"/> T.
/// </summary>
public static List<EnumPair<T>> GetValuePairList()
{
List<EnumPair<T>> list = new List<EnumPair<T>>();
EnumPair<T> pair = new EnumPair<T>();
foreach (var item in Enum.GetValues(typeof(T)))
{
pair = new EnumPair<T>();
pair.EnumValue = (T)item;
pair.EnumStringValue = ((T)item).ToString();
list.Add(pair);
}
return list;
}
/// <summary>
/// Implicit conversion from enum value to <see cref="EnumPair<>"/> from that enum.
/// </summary>
/// <param name="e">The enum value to convert to.</param>
/// <returns>A <see cref="EnumPair<>"/> to the enum value.</returns>
public static implicit operator EnumPair<T>(T e)
{
Type t = typeof(EnumPair<>).MakeGenericType(e.GetType());
return new EnumPair<T>((T)e, ((T)e).ToString());
}
#endregion
}
You can try something like this:
ddTemplates.DataSource =
Enum.GetValues(typeof(EmailTemplateType))
.Cast<EmailTemplateType>().ToList()
.Select(v => new KeyValuePair<int, string>((int)v, v.ToString())).ToList();
In the below code in xml documentations there is mismatch between the names of parameters in method's arguments and name of parameters in xml documentation. Is there any way to auto correct the xml documentation signature or any feature provided in resharper to auto correct the xml documentation.
#region Get Images
/// <summary>
/// Get Images
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
/// <returns></returns>
public Collection<UserImage> GetImages()
{
return GetImages("");
}
/// <summary>
/// Get Images
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
/// <returns></returns>
public Collection<UserImage> GetImages(string imageType)
{
return GetImages(0, imageType);
}
/// <summary>
/// Get Images
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
/// <returns></returns>
public Collection<UserImage> GetImages(int imageId)
{
return GetImages(imageId, "");
}
/// <summary>
/// Get Images
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
/// <returns></returns>
public Collection<UserImage> GetImages(int imageId,string imageType)
{
return null;
}
#endregion
For example i want the method with xml documentation like this:
/// <summary>
/// Get Images
/// </summary>
/// <param name="imageId"></param>
/// <param name="imageType"></param>
/// <returns></returns>
public Collection<UserImage> GetImages(int imageId,string imageType)
{
return null;
}
#endregion
GhostDoc will do this for you. After installation you get a new context menu item in VS 'Document this' (and a corresponding keyboard shortcut).
If no XML comments are present, it will add them. If they are already present, they should get updated as you require.
http://submain.com/products/ghostdoc.aspx
The only way I know to "auto correct" xml with R# is to delete the existing xml documentation and hit /// again. Sorry I don't have a better answer.
I believe it's not possible because R# doesn't what need to correct the xml documentation or method signature.