For a time-critical media presentation application, it is important that media files be presented right at the instance when the user selects it. Those files reside in a truly humongous directory structure, comprised of thousands of media files.
Clearly, caching the media files in a MemoryStream is the way to go; however, due to the sheer amount of files, it’s not feasible to cache each file entirely. Instead, my idea is to pre-cache a certain buffer of each file, and once the file is presented, play from that cache until the rest of the file is loaded from the hard disk.
What I don’t see is how to “concatenate” both the MemoryStream and the FileStream so as to provide a seamless playback experience. I’m not very strong in data streams (yet), and I see several problems:
How does one keep track of the current read position within the MemoryStream and provide that to the FileStream without the MemoryStream reading more than that?
How does one switch from one stream to the other without having both streams either partially overlap each other or creating a “playback break”?
If using a queue of streams (as suggested in How do I concatenate two System.Io.Stream instances into one?), how can I specify that the second stream has to be ready for read access instantaneously after the first stream is done? Here, in particular, I don’t see how the MemoryStream would help at all, since the FileStream, as second one in the queue, would only begin accessing the hard disk once it’s actually used.
Is it really a feasible approach to have literally hundreds, if not thousands of open streams at once?
Note that I don’t need write access—reading is fully sufficient for the problem at hand. Also, this question is similar to Composite Stream Wrapper providing partial MemoryStream and full original Stream, but the solution provided there is a bug fix for Windows Phone 8 that doesn’t apply in my case.
I’d very much like to widen my rather limited understanding of this, so any help is greatly appreciated.
I would suggest something like the following solution:
Inherit your own CachableFileStream from FileStream
Implement a very simple Cache which uses a data structure you prefer (like a Queue)
Allow Preloading data into the internal cache
Allow Reloading data into the internal cache
Modify the original Read behaviour in a way, that your cache is used
To give you an idea of my idea I would suggest some implementation like the following one:
The usage could be like that:
CachableFileStream cachedStream = new CachableFileStream(...)
{
PreloadSize = 8192,
ReloadSize = 4096,
};
// Force preloading data into the cache
cachedStream.Preload();
...
cachedStream.Read(buffer, 0, buffer.Length);
...
Warning: The code below is neither correctly tested nor ideal - this shall just give you an idea!
The CachableFileStream class:
using System;
using System.IO;
using System.Threading.Tasks;
/// <summary>
/// Represents a filestream with cache.
/// </summary>
public class CachableFileStream : FileStream
{
private Cache<byte> cache;
private int preloadSize;
private int reloadSize;
/// <summary>
/// Gets or sets the amount of bytes to be preloaded.
/// </summary>
public int PreloadSize
{
get
{
return this.preloadSize;
}
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException(nameof(value), "The specified preload size must not be smaller than or equal to zero.");
this.preloadSize = value;
}
}
/// <summary>
/// Gets or sets the amount of bytes to be reloaded.
/// </summary>
public int ReloadSize
{
get
{
return this.reloadSize;
}
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException(nameof(value), "The specified reload size must not be smaller than or equal to zero.");
this.reloadSize = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="CachableFileStream"/> class with the specified path and creation mode.
/// </summary>
/// <param name="path">A relative or absolute path for the file that the current CachableFileStream object will encapsulate</param>
/// <param name="mode">A constant that determines how to open or create the file.</param>
/// <exception cref="System.ArgumentException">
/// Path is an empty string (""), contains only white space, or contains one or more invalid characters.
/// -or- path refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in an NTFS environment.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// Path refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in a non-NTFS environment.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// Path is null.
/// </exception>
/// <exception cref="System.Security.SecurityException">
/// The caller does not have the required permission.
/// </exception>
/// <exception cref="System.IO.FileNotFoundException">
/// The file cannot be found, such as when mode is FileMode.Truncate or FileMode.Open, and the file specified by path does not exist.
/// The file must already exist in these modes.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error, such as specifying FileMode.CreateNew when the file specified by path already exists, occurred.-or-The stream has been closed.
/// </exception>
/// <exception cref="System.IO.DirectoryNotFoundException">
/// The specified path is invalid, such as being on an unmapped drive.
/// </exception>
/// <exception cref="System.IO.PathTooLongException">
/// The specified path, file name, or both exceed the system-defined maximum length.
/// For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Mode contains an invalid value
/// </exception>
public CachableFileStream(string path, FileMode mode) : base(path, mode)
{
this.cache = new Cache<byte>();
this.cache.CacheIsRunningLow += CacheIsRunningLow;
}
/// <summary>
/// Reads a block of bytes from the stream and writes the data in a given buffer.
/// </summary>
/// <param name="array">
/// When this method returns, contains the specified byte array with the values between
/// offset and (offset + count - 1) replaced by the bytes read from the current source.
/// </param>
/// <param name="offset">The byte offset in array at which the read bytes will be placed.</param>
/// <param name="count">The maximum number of bytes to read.</param>
/// <returns>
/// The total number of bytes read into the buffer. This might be less than the number
/// of bytes requested if that number of bytes are not currently available, or zero
/// if the end of the stream is reached.
/// </returns>
/// <exception cref="System.ArgumentNullException">
/// Array is null.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Offset or count is negative.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support reading.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="System.ArgumentException">
/// Offset and count describe an invalid range in array.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
public override int Read(byte[] array, int offset, int count)
{
int readBytesFromCache;
for (readBytesFromCache = 0; readBytesFromCache < count; readBytesFromCache++)
{
if (this.cache.Size == 0)
break;
array[offset + readBytesFromCache] = this.cache.Read();
}
if (readBytesFromCache < count)
readBytesFromCache += base.Read(array, offset + readBytesFromCache, count - readBytesFromCache);
return readBytesFromCache;
}
/// <summary>
/// Preload data into the cache.
/// </summary>
public void Preload()
{
this.LoadBytesFromStreamIntoCache(this.PreloadSize);
}
/// <summary>
/// Reload data into the cache.
/// </summary>
public void Reload()
{
this.LoadBytesFromStreamIntoCache(this.ReloadSize);
}
/// <summary>
/// Loads bytes from the stream into the cache.
/// </summary>
/// <param name="count">The number of bytes to read.</param>
private void LoadBytesFromStreamIntoCache(int count)
{
byte[] buffer = new byte[count];
int readBytes = base.Read(buffer, 0, buffer.Length);
this.cache.AddRange(buffer, 0, readBytes);
}
/// <summary>
/// Represents the event handler for the CacheIsRunningLow event.
/// </summary>
/// <param name="sender">The sender of the event.</param>
/// <param name="e">Event arguments.</param>
private void CacheIsRunningLow(object sender, EventArgs e)
{
this.cache.WarnIfRunningLow = false;
new Task(() =>
{
Reload();
this.cache.WarnIfRunningLow = true;
}).Start();
}
}
The Cache class:
using System;
using System.Collections.Concurrent;
/// <summary>
/// Represents a generic cache.
/// </summary>
/// <typeparam name="T">Defines the type of the items in the cache.</typeparam>
public class Cache<T>
{
private ConcurrentQueue<T> queue;
/// <summary>
/// Is executed when the number of items within the cache run below the
/// specified warning limit and WarnIfRunningLow is set.
/// </summary>
public event EventHandler CacheIsRunningLow;
/// <summary>
/// Gets or sets a value indicating whether the CacheIsRunningLow event shall be fired or not.
/// </summary>
public bool WarnIfRunningLow
{
get;
set;
}
/// <summary>
/// Gets or sets a value that represents the lower warning limit.
/// </summary>
public int LowerWarningLimit
{
get;
set;
}
/// <summary>
/// Gets the number of items currently stored in the cache.
/// </summary>
public int Size
{
get;
private set;
}
/// <summary>
/// Initializes a new instance of the <see cref="Cache{T}"/> class.
/// </summary>
public Cache()
{
this.queue = new ConcurrentQueue<T>();
this.Size = 0;
this.LowerWarningLimit = 1024;
this.WarnIfRunningLow = true;
}
/// <summary>
/// Adds an item into the cache.
/// </summary>
/// <param name="item">The item to be added to the cache.</param>
public void Add(T item)
{
this.queue.Enqueue(item);
this.Size++;
}
/// <summary>
/// Adds the items of the specified array to the end of the cache.
/// </summary>
/// <param name="items">The items to be added.</param>
public void AddRange(T[] items)
{
this.AddRange(items, 0, items.Length);
}
/// <summary>
/// Adds the specified count of items of the specified array starting
/// from offset to the end of the cache.
/// </summary>
/// <param name="items">The array that contains the items.</param>
/// <param name="offset">The offset that shall be used.</param>
/// <param name="count">The number of items that shall be added.</param>
public void AddRange(T[] items, int offset, int count)
{
for (int i = offset; i < count; i++)
this.Add(items[i]);
}
/// <summary>
/// Reads one item from the cache.
/// </summary>
/// <returns>The item that has been read from the cache.</returns>
/// <exception cref="System.InvalidOperationException">
/// The cache is empty.
/// </exception>
public T Read()
{
T item;
if (!this.queue.TryDequeue(out item))
throw new InvalidOperationException("The cache is empty.");
this.Size--;
if (this.WarnIfRunningLow &&
this.Size < this.LowerWarningLimit)
{
this.CacheIsRunningLow?.Invoke(this, EventArgs.Empty);
}
return item;
}
/// <summary>
/// Peeks the next item from cache.
/// </summary>
/// <returns>The item that has been read from the cache (without deletion).</returns>
/// <exception cref="System.InvalidOperationException">
/// The cache is empty.
/// </exception>
public T Peek()
{
T item;
if (!this.queue.TryPeek(out item))
throw new InvalidOperationException("The cache is empty.");
return item;
}
}
I hope this helps, have fun ;-)
Related
Using C# i'm trying to retrieve the name of the song that is currently playing and display it on a listBox, so every song that plays, it's shown in the listbox.
Using System;
Using WMPLib;
public IWMPMedia currentMedia { get; set; }
private void button1_Click(object sender, EventArgs e)
{
Player = new WMPLib.WindowsMediaPlayer();
string song = Player.currentMedia.name.ToString();
listBox1.Items.Add(song);
}
But it throws me the exception.
"Object reference not set to an instance of an object" here:
string song = Player.currentMedia.name.ToString();
Does anyone knows how to solve this?
You will have to use COM/OLE to do this. I did a program that did exactly that a little while ago, unfortunately tho I cannot find my client code, but I still have the code that implements IOleClientSite/IOleServiceProvider for WMPLib.
I found that code at the following URL:
http://sirayuki.sakura.ne.jp/WmpSample/WmpRemote.zip
Its some code that was writen by Jonathan Dibble, a Microsoft employee if I remember correctly. There is a CHM in the Zip with some explanation on each of the classes.
Heres the code that I still have, in case the link goes down, but like I said I cannot find my code that uses it. It worked almost correctly but I remember that one of the bug left was that it would leave behind wmplayer.exe processes after the media player and my application were closed.
UPDATE!
found some client code and a slighlty modified version of RemotedWindowsMediaPlayer.cs
I just found some coded that I tested this with, and it works. Its from a Winform project, and you need to reference WMPLib for this to work.
In my form I added a button and this code:
/// <summary>
/// Default Constructor
/// </summary>
RemotedWindowsMediaPlayer rm;
public FrmMain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//Call me old fashioned - I like to do this stuff manually. You can do a drag
//drop if you like, it won't change the results.
rm = new RemotedWindowsMediaPlayer();
rm.Dock = System.Windows.Forms.DockStyle.Top;
panel1.Controls.Add(rm);
return;
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(((WMPLib.IWMPPlayer4)rm.GetOcx()).currentMedia.sourceURL);
}
RemotedWindowsMediaPLayer.cs:
namespace RemoteWMP
{
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using WMPLib;
/// <summary>
/// This is the actual Windows Media Control.
/// </summary>
[System.Windows.Forms.AxHost.ClsidAttribute("{6bf52a52-394a-11d3-b153-00c04f79faa6}")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class RemotedWindowsMediaPlayer : System.Windows.Forms.AxHost,
IOleServiceProvider,
IOleClientSite
{
/// <summary>
/// Used to attach the appropriate interface to Windows Media Player.
/// In here, we call SetClientSite on the WMP Control, passing it
/// the dotNet container (this instance.)
/// </summary>
protected override void AttachInterfaces()
{
try
{
//Get the IOleObject for Windows Media Player.
IOleObject oleObject = this.GetOcx() as IOleObject;
if (oleObject != null)
{
//Set the Client Site for the WMP control.
oleObject.SetClientSite(this as IOleClientSite);
// Try and get the OCX as a WMP player
if (this.GetOcx() as IWMPPlayer4 == null)
{
throw new Exception(string.Format("OCX is not an IWMPPlayer4! GetType returns '{0}'",
this.GetOcx().GetType()));
}
}
else
{
throw new Exception("Failed to get WMP OCX as an IOleObject?!");
}
return;
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
#region IOleServiceProvider Memebers - Working
/// <summary>
/// During SetClientSite, WMP calls this function to get the pointer to <see cref="RemoteHostInfo"/>.
/// </summary>
/// <param name="guidService">See MSDN for more information - we do not use this parameter.</param>
/// <param name="riid">The Guid of the desired service to be returned. For this application it will always match
/// the Guid of <see cref="IWMPRemoteMediaServices"/>.</param>
/// <returns></returns>
IntPtr IOleServiceProvider.QueryService(ref Guid guidService, ref Guid riid)
{
//If we get to here, it means Media Player is requesting our IWMPRemoteMediaServices interface
if (riid == new Guid("cbb92747-741f-44fe-ab5b-f1a48f3b2a59"))
{
IWMPRemoteMediaServices iwmp = new RemoteHostInfo();
return Marshal.GetComInterfaceForObject(iwmp, typeof(IWMPRemoteMediaServices));
}
throw new System.Runtime.InteropServices.COMException("No Interface", (int) HResults.E_NOINTERFACE);
}
#endregion
#region IOleClientSite Members
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException">E_NOTIMPL</exception>
void IOleClientSite.SaveObject()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
object IOleClientSite.GetMoniker(uint dwAssign, uint dwWhichMoniker)
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
object IOleClientSite.GetContainer()
{
return (int)HResults.E_NOINTERFACE;
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.ShowObject()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.OnShowWindow(bool fShow)
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.RequestNewObjectLayout()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
#endregion
/// <summary>
/// Default Constructor.
/// </summary>
public RemotedWindowsMediaPlayer() :
base("6bf52a52-394a-11d3-b153-00c04f79faa6")
{
}
}
}
RemoteHostInfo.cs
using System;
namespace RemoteWMP
{
using System.Runtime.InteropServices;
/// <summary>
/// This class contains the information to return to Media Player about our remote service.
/// </summary>
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class RemoteHostInfo :
IWMPRemoteMediaServices
{
#region IWMPRemoteMediaServices Members
/// <summary>
/// Returns "Remote" to tell media player that we want to remote the WMP application.
/// </summary>
/// <returns></returns>
public string GetServiceType()
{
return "Remote";
}
/// <summary>
/// The Application Name to show in Windows Media Player switch to menu
/// </summary>
/// <returns></returns>
public string GetApplicationName()
{
return System.Diagnostics.Process.GetCurrentProcess().ProcessName;
}
/// <summary>
/// Not in use, see MSDN for more info.
/// </summary>
/// <param name="name"></param>
/// <param name="dispatch"></param>
/// <returns></returns>
public HResults GetScriptableObject(out string name, out object dispatch)
{
name = null;
dispatch = null;
//return (int) HResults.S_OK;//NotImplemented
return HResults.E_NOTIMPL;
}
/// <summary>
/// For skins, not in use, see MSDN for more info.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public HResults GetCustomUIMode(out string file)
{
file = null;
return HResults.E_NOTIMPL;//NotImplemented
}
#endregion
}
}
COM Interfaces.cs
using System;
namespace RemoteWMP
{
using System.Runtime.InteropServices;
#region Useful COM Enums
/// <summary>
/// Represents a collection of frequently used HRESULT values.
/// You may add more HRESULT VALUES, I've only included the ones used
/// in this project.
/// </summary>
public enum HResults
{
/// <summary>
/// HRESULT S_OK
/// </summary>
S_OK = unchecked((int)0x00000000),
/// <summary>
/// HRESULT S_FALSE
/// </summary>
S_FALSE = unchecked((int)0x00000001),
/// <summary>
/// HRESULT E_NOINTERFACE
/// </summary>
E_NOINTERFACE = unchecked((int)0x80004002),
/// <summary>
/// HRESULT E_NOTIMPL
/// </summary>
E_NOTIMPL = unchecked((int)0x80004001),
/// <summary>
/// USED CLICKED CANCEL AT SAVE PROMPT
/// </summary>
OLE_E_PROMPTSAVECANCELLED = unchecked((int)0x8004000C),
}
/// <summary>
/// Enumeration for <see cref="IOleObject.GetMiscStatus"/>
/// </summary>
public enum DVASPECT
{
/// <summary>
/// See MSDN for more information.
/// </summary>
Content = 1,
/// <summary>
/// See MSDN for more information.
/// </summary>
Thumbnail = 2,
/// <summary>
/// See MSDN for more information.
/// </summary>
Icon = 3,
/// <summary>
/// See MSDN for more information.
/// </summary>
DocPrint = 4
}
/// <summary>
/// Emumeration for <see cref="IOleObject.Close"/>
/// </summary>
public enum TAGOLECLOSE :uint{
OLECLOSE_SAVEIFDIRTY = unchecked((int)0),
OLECLOSE_NOSAVE = unchecked((int)1),
OLECLOSE_PROMPTSAVE = unchecked((int)2)
}
#endregion
#region IWMPRemoteMediaServices
/// <summary>
/// Interface used by Media Player to determine WMP Remoting status.
/// </summary>
[ComImport,
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("CBB92747-741F-44fe-AB5B-F1A48F3B2A59")]
public interface IWMPRemoteMediaServices
{
/// <summary>
/// Service type.
/// </summary>
/// <returns><code>Remote</code> if the control is to be remoted (attached to WMP.)
/// <code>Local</code>if this is an independent WMP instance not connected to WMP application. If you want local, you shouldn't bother
/// using this control!
/// </returns>
[return: MarshalAs(UnmanagedType.BStr)]
string GetServiceType();
/// <summary>
/// Value to display in Windows Media Player Switch To Application menu option (under View.)
/// </summary>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.BStr)]
string GetApplicationName();
/// <summary>
/// Not in use, see MSDN for details.
/// </summary>
/// <param name="name"></param>
/// <param name="dispatch"></param>
/// <returns></returns>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults GetScriptableObject([MarshalAs(UnmanagedType.BStr)] out string name,
[MarshalAs(UnmanagedType.IDispatch)] out object dispatch);
/// <summary>
/// Not in use, see MSDN for details.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults GetCustomUIMode([MarshalAs(UnmanagedType.BStr)] out string file);
}
#endregion
#region IOleServiceProvider
/// <summary>
/// Interface used by Windows Media Player to return an instance of IWMPRemoteMediaServices.
/// </summary>
[ComImport,
GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true)]
public interface IOleServiceProvider
{
/// <summary>
/// Similar to QueryInterface, riid will contain the Guid of an object to return.
/// In our project we will look for <see cref="IWMPRemoteMediaServices"/> Guid and return the object
/// that implements that interface.
/// </summary>
/// <param name="guidService"></param>
/// <param name="riid">The Guid of the desired Service to provide.</param>
/// <returns>A pointer to the interface requested by the Guid.</returns>
IntPtr QueryService(ref Guid guidService, ref Guid riid);
}
/// <summary>
/// This is an example of an INCORRECT entry - do not use, unless you want your app to break.
/// </summary>
[ComImport,
GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true)]
public interface BadIOleServiceProvider
{
/// <summary>
/// This is incorrect because it causes our return interface to be boxed
/// as an object and a COM callee may not get the correct pointer.
/// </summary>
/// <param name="guidService"></param>
/// <param name="riid"></param>
/// <returns></returns>
/// <example>
/// For an example of a correct definition, look at <see cref="IOleServiceProvider"/>.
/// </example>
[return: MarshalAs(UnmanagedType.Interface)]
object QueryService(ref Guid guidService, ref Guid riid);
}
#endregion
#region IOleClientSite
/// <summary>
/// Need to implement this interface so we can pass it to <see cref="IOleObject.SetClientSite"/>.
/// All functions return E_NOTIMPL. We don't need to actually implement anything to get
/// the remoting to work.
/// </summary>
[ComImport,
ComVisible(true),
Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ]
public interface IOleClientSite
{
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void SaveObject();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
[return: MarshalAs(UnmanagedType.Interface)]
object GetMoniker(uint dwAssign, uint dwWhichMoniker);
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
[return: MarshalAs(UnmanagedType.Interface)]
object GetContainer();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void ShowObject();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void OnShowWindow(bool fShow);
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void RequestNewObjectLayout();
}
#endregion
#region IOleObject
/// <summary>
/// This interface is implemented by WMP ActiveX/COM control.
/// The only function we need is <see cref="SetClientSite"/>.
/// </summary>
[ComImport, ComVisible(true),
Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
/// <summary>
/// Used to pass our custom <see cref="IOleClientSite"/> object to WMP. The object we pass must also
/// implement <see cref="IOleServiceProvider"/> to work right.
/// </summary>
/// <param name="pClientSite">The <see cref="IOleClientSite"/> to pass.</param>
void SetClientSite(IOleClientSite pClientSite);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
IOleClientSite GetClientSite();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetHostNames(
[MarshalAs(UnmanagedType.LPWStr)]string szContainerApp,
[MarshalAs(UnmanagedType.LPWStr)]string szContainerObj);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Close(uint dwSaveOption);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetMoniker(uint dwWhichMoniker, object pmk);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object GetMoniker(uint dwAssign, uint dwWhichMoniker);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void InitFromData(object pDataObject, bool fCreation, uint dwReserved);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
object GetClipboardData(uint dwReserved);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void DoVerb(uint iVerb, uint lpmsg, [MarshalAs(UnmanagedType.Interface)]object pActiveSite,
uint lindex, uint hwndParent, uint lprcPosRect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object EnumVerbs();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Update();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults IsUpToDate();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
Guid GetUserClassID();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.LPWStr)]
string GetUserType(uint dwFormOfType);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetExtent(uint dwDrawAspect, [MarshalAs(UnmanagedType.Interface)] object psizel);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object GetExtent(uint dwDrawAspect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
uint Advise([MarshalAs(UnmanagedType.Interface)]object pAdvSink);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Unadvise(uint dwConnection);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object EnumAdvise();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
uint GetMiscStatus([MarshalAs(UnmanagedType.U4)] DVASPECT dwAspect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetColorScheme([MarshalAs(UnmanagedType.Interface)] object pLogpal);
}
#endregion
}
I'm making a BRRES to BFRES converter. For some reason, the MDL0 section seems to be always null when debugging. Here is the code for the Brres file loader:
/// <summary>
/// Represents a set of properties controlling the load of a <see cref="Brres.BrresFile"/>.
/// </summary>
internal class BrresLoaderContext
{
// ---- CONSTRUCTORS -------------------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="BrresLoaderContext"/> class for the given <see cref="BrresFile"/>
/// instance using the given <see cref="BinaryDataReader"/>.
/// </summary>
/// <param name="BrresFile">The <see cref="BrresFile"/> instance to load the data in.</param>
/// <param name="reader">The <see cref="BinaryDataReader"/> to use for reading the data.</param>
internal BrresLoaderContext(BrresFile brresFile, BinaryDataReader reader)
{
BrresFile = brresFile;
Reader = reader;
Warnings = new List<string>();
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the <see cref="BrresFile"/> instance which is loaded to.
/// </summary>
internal BrresFile BrresFile
{
get;
private set;
}
/// <summary>
/// Gets the <see cref="BinaryDataReader"/> which is used to read data from the input stream.
/// </summary>
internal BinaryDataReader Reader
{
get;
private set;
}
/// <summary>
/// Gets or sets the warnings raised after loading the Brres file.
/// </summary>
internal List<string> Warnings
{
get;
private set;
}
}
I mostly didn't update comments.
So why is it null?
I'm trying to create a linked list for my personal library that can handle EVERYTHING. I'm trying to write it so that it can 'equally' easily hand int, null,DateTime or Class and I wanted it to be easily extendable, so that if I wanted to quickly make stack out of it, I can just write push, pop, and peek methods and so forth.
Currently, my code looks like this. Note that I use 'Base' as my generic type.
namespace ClassLibrary1
{
public class LinkedList<Base> where Base : class
{
public class Node
{
private Node next;
private Node prev;
private Base value;
/// <summary>
/// Constructor for Nodes of Circular Linked List class.
/// Calls overloaded constructor for no previous or next provided.
/// O(1)
/// </summary>
/// <param name="value">The value to be stored. Can use tuple for associations</param>
public Node(Base value)
{
new Node(null, null, value);
}
/// <summary>
/// Constructor for nodes of Circular Linked List class.
/// O(1)
/// </summary>
/// <param name="prev">The previous node in the linked list</param>
/// <param name="next">The next node in the linked list</param>
/// <param name="value">The value to be stored</param>
public Node(Node prev, Node next, Base value)
{
this.prev = prev;
this.next = next;
this.value = value;
}
/// <summary>
/// Sets the 'next' attribute of the node to the passed value.
/// O(1)
/// Chainable
/// </summary>
/// <param name="next">The new value of the 'next' attribute.</param>
/// <returns>Chainable(Node, this)</returns>
public Node setNext(Node next)
{
this.next = next;
return this;
}
/// <summary>
/// Sets the 'prev' attribute of the node to the passed value
/// O(1)
/// Chainable
/// </summary>
/// <param name="prev">The new value of the 'prev' attribute to denote the previous node</param>
/// <returns>Chainable(Node, this)</returns>
public Node setPrev(Node prev)
{
this.prev = prev;
return this;
}
/// <summary>
/// Changes the stored value of type Base to the passed value.
/// O(1)
/// Chainable
/// </summary>
/// <param name="value">The new value to be stored with the node</param>
/// <returns>Chainable(Node, this)</returns>
public Node setVal(Base value)
{
this.value = value;
return this;
}
/// <summary>
/// Returns the next node in the linked list.
/// O(1)
/// </summary>
/// <returns>The next node in the linked list.(Node)</returns>
public Node getNext()
{
return this.next;
}
/// <summary>
/// Returns the previous node in the linked list.
/// O(1)
/// </summary>
/// <returns>The previous node in the linked list.(Node)</returns>
public Node getPrev()
{
return this.prev;
}
/// <summary>
/// Returns the value stored at this node.
/// O(1)
/// </summary>
/// <returns>The value stored at this node.(Base)</returns>
public Base getVal()
{
return this.value;
}
}
public Node head;
public bool duplicates;
public bool hasNullValues;
public bool throwNullError;
/// <summary>
/// Constructor for the LinkedList. Creates a null head node.
/// Duplication defaulted to false
/// O(1)
/// </summary>
public LinkedList()
{
this.head = new Node(null);
this.head.setNext(this.head).setPrev(this.head);
this.duplicates = false;
this.hasNullValues = false;
this.throwNullError = false;
}
/// <summary>
/// Allows duplication for the linked list.
/// O(1)
/// Chainable attribute.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> hasDuplicates()
{
this.duplicates = true;
return this;
}
/// <summary>
/// Allows the structure to store null values in nodes.
/// O(1)
/// Chainable.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> hasNulls()
{
this.hasNullValues = true;
return this;
}
/// <summary>
/// Causes the structure to throw a null error when a null value is inserted.
/// If hasNulls is off, turns it on.
/// O(1)
/// Chainable.
/// </summary>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> throwsNulls()
{
if (!this.hasNullValues)
{
this.hasNullValues = true;
}
this.throwNullError = true;
return this;
}
/// <summary>
/// Iff duplicates not allowed, searches for value in list. Throws error if duplicate found.
/// Creates a new node at the end of the list, then links it to the head node.
/// O(length) [if hasDuplicates()]
/// O(1) [if else]
/// Chainable
/// </summary>
/// <param name="value">Value stored at the new node in the list</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> add(Base value)
{
if (!duplicates)
{
if (search(value) != null)
{
throw new Exception("Value already exists in the linked list.");
}
}
if (!this.hasNullValues && value != null)
{
if (this.throwNullError)
{
throw new Exception("Cannot insert null values");
}
else
{
return this;
}
}
Node newNode = new Node(value);
this.head.getPrev().setNext(newNode);
this.head.setPrev(newNode);
return this;
}
/// <summary>
/// Iterates through the list until first such node for with a matching value is found.
/// Returns null if no matches found.
/// Use searchAll to find duplicates.
/// O(length)
/// </summary>
/// <param name="value">The value to be searched for.</param>
/// <returns>First node with the desired value(Node?)</returns>
public Node search(Base value)
{
Node temp = this.head.getNext();
while (!temp.getVal().Equals(value))
{
if (temp.Equals(this.head))
{
return null;
}
temp = temp.getNext();
}
return temp;
}
/// <summary>
/// If value doesn't exist in the list, throws an exception.
/// Deletes the first node found with the chosen value.
/// Use DeleteAll to delete all instances.
/// Chainable.
/// O(length)
/// </summary>
/// <param name="value">Value to be removed from the list.</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> delete(Base value)
{
try{
return delete(search(value));
}
catch(Exception e){
throw new Exception("Node to be deleted not found");
}
}
/// <summary>
/// Removes all pointers to the passed node.
/// O(1)
/// </summary>
/// <param name="tbd">The node to be deleted.</param>
/// <returns>Chainable.(LinkedList<Base>, this)</returns>
public LinkedList<Base> delete(Node tbd)
{
if (tbd.Equals(this.head))
{
throw new Exception("Cannot delete head node");
}
else
{
tbd.getPrev().setNext(tbd.getNext());
tbd.getNext().setPrev(tbd.getPrev());
}
return this;
}
/// <summary>
/// Returns a LinkedList of all nodes containing the desired value.
/// O(length)
/// </summary>
/// <param name="value">The value to be found.</param>
/// <returns>A LinkedList of Nodes with matching values.(LinkedList<Node>)</returns>
public LinkedList<Node> searchAll(Base value)
{
LinkedList<Node> returnList = new LinkedList<Node>();
Node temp = this.head.getNext();
while (!temp.Equals(this.head))
{
if (temp.getVal().Equals(value))
{
returnList.add(temp);
}
temp = temp.getNext();
}
return returnList;
}
/// <summary>
/// Returns the first Node in the Linked List.
/// O()
/// </summary>
/// <returns>First non-head node in the list.(Node)</returns>
public Node firstOrDefault()
{
return this.head.getNext();
}
/// <summary>
/// Returns the value of the first node in the list.
/// O(1)
/// </summary>
/// <returns>FIrst non-head </returns>
public Base firstVal()
{
return this.head.getNext().getVal();
}
/// <summary>
/// Gets the last node in the linked list.
/// O(1)
/// </summary>
/// <returns>The last node in the linked list.(Node)</returns>
public Node tail()
{
return this.head.getPrev();
}
/// <summary>
/// Returns the value of the last node in the linked list.
/// O(1)
/// </summary>
/// <returns>VThe value of the tail node.(Base)</returns>
public Base tailVal()
{
return this.head.getPrev().getVal();
}
public static void Main()
{
LinkedLis t<Int32> mine = new LinkedList<Int32>();
}
}
}
However, it gives Red Text under the Int32, saying "The type 'int' must be a reference type in order to use it as a parameter 'Base' in the generic type or method ---this---.
Tell me if you would like me to remove the comments, I'm not sure if that makes it harder or easier to solve.
Because you declared a constraint on a Base type to be a class (a reference type):
public class LinkedList<Base> where Base : class
It exactly forbids using Int32, because it's a value type and is different from a required reference type.
new LinkedList<Int32>()
So, to fix this particular problem, you would need to to create a wrapper class for your integer values.
Before you do this though, check your intentions to store any type in your linked list. Doing so you will strip you off all advantages of C# as a strongly typed language.
And as it was mentioned before, unless you write this code as a pure academic exercise, you should use an existing .NET LinkedList and possibly extend/inherit it, if you need more functionality.
Update: I assumed it went without saying, but to make it crystal clear don't forget that Nullable is a struct, not a class, so you cannot use "cheats" like int?.
I am currently trying to retrieve the signal strength from a wireless access point using the wlanapi.dll WlanQueryInterface call.
Here is my api declaration
[DllImport("wlanapi.dll", SetLastError = true)]
private static extern UInt32 WlanQueryInterface(IntPtr hClientHandle, ref Guid pInterfaceGuid, WLAN_INTF_OPCODE OpCode, IntPtr pReserved, out Int32 pdwDataSize, ref IntPtr ppData, IntPtr pWlanOpCodeValueType);
The problem is when I look at the wlanSignalStrength entry in the WLAN_ASSOCIATION_ATTRIBUTES structure it is set to 5400. Microsoft API documentation says that it should be a value between 0 - 100.
Here is my structure declaration:
/// <summary>
/// Structure contains association attributes for a connection.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WLAN_ASSOCIATION_ATTRIBUTES
{
/// <summary>
/// A DOT11_SSID structure that contains the SSID of the association.
/// </summary>
public DOT11_SSID dot11Ssid;
/// <summary>
/// A DOT11_BSS_TYPE value that specifies whether the network is infrastructure or ad hoc.
/// </summary>
public DOT11_BSS_TYPE dot11BssType;
/// <summary>
/// A DOT11_MAC_ADDRESS that contains the BSSID of the association.
/// </summary>
public DOT11_MAC_ADDRESS dot11Bssid;
/// <summary>
/// A DOT11_PHY_TYPE value that indicates the physical type of the association
/// </summary>
public DOT11_PHY_TYPE dot11PhyType;
/// <summary>
/// The position of the DOT11_PHY_TYPE value in the structure containing the list of PHY types.
/// </summary>
public ulong uDot11PhyIndex;
/// <summary>
/// A percentage value that represents the signal quality of the network.
/// </summary>
public Int32 wlanSignalQuality;
/// <summary>
/// Contains the receiving rate of the association.
/// </summary>
public ulong ulRxRate;
/// <summary>
/// Contains the transmission rate of the association.
/// </summary>
public ulong ulTxRate;
}
Here is my call to WlanQueryInterface:
Int32 iDataSize;
IntPtr ppData = IntPtr.Zero;
WLAN_CONNECTION_ATTRIBUTES wcaAttributes = new WLAN_CONNECTION_ATTRIBUTES();
String[] sReturn = new String[4];
if (WlanQueryInterface(pClientHandle, ref gInterfaceGUID, WLAN_INTF_OPCODE.wlan_intf_opcode_current_connection, IntPtr.Zero, out iDataSize, ref ppData, IntPtr.Zero) == ERROR_SUCCESS)
{
wcaAttributes = (WLAN_CONNECTION_ATTRIBUTES)Marshal.PtrToStructure(ppData, typeof(WLAN_CONNECTION_ATTRIBUTES));
sReturn[0] = wcaAttributes.wlanAssociationAttributes.dot11Ssid.ucSSID;
sReturn[1] = wcaAttributes.strProfileName;
sReturn[2] = String.Format("{0:X2}-{1:X2}-{2:X2}-{3:X2}-{4:X2}-{5:X2}", wcaAttributes.wlanAssociationAttributes.dot11Bssid.bOne, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bTwo, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bThree, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bFour, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bFive, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bSix);
sReturn[3] = wcaAttributes.wlanAssociationAttributes.wlanSignalQuality.ToString(); //This returns 5400 when the actual strength is ~99
WlanFreeMemory(ppData);
return sReturn;
}
else
{
throw new Exception("Unable to get interface connected SSID.");
}
Does anyone see what I am doing wrong? Thanks in advance!
I finally got it fixed. I had to set the LayoutKind for the WLAN_ASSOCIATION_ATTRIBUTES to Explicit and set the charset to Unicode.
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
private struct WLAN_ASSOCIATION_ATTRIBUTES
{
/// <summary>
/// A DOT11_SSID structure that contains the SSID of the association.
/// </summary>
[FieldOffset(0)]
public DOT11_SSID dot11Ssid;
/// <summary>
/// A DOT11_BSS_TYPE value that specifies whether the network is infrastructure or ad hoc.
/// </summary>
[FieldOffset(0x24)]
public DOT11_BSS_TYPE dot11BssType;
/// <summary>
/// A DOT11_MAC_ADDRESS that contains the BSSID of the association.
/// </summary>
[FieldOffset(40)]
public DOT11_MAC_ADDRESS dot11Bssid;
/// <summary>
/// A DOT11_PHY_TYPE value that indicates the physical type of the association
/// </summary>
[FieldOffset(0x30)]
public DOT11_PHY_TYPE dot11PhyType;
/// <summary>
/// The position of the DOT11_PHY_TYPE value in the structure containing the list of PHY types.
/// </summary>
[FieldOffset(0x34)]
public ulong uDot11PhyIndex;
/// <summary>
/// A percentage value that represents the signal quality of the network.
/// </summary>
[FieldOffset(0x38)]
public Int32 wlanSignalQuality;
/// <summary>
/// Contains the receiving rate of the association.
/// </summary>
[FieldOffset(60)]
public ulong ulRxRate;
/// <summary>
/// Contains the transmission rate of the association.
/// </summary>
[FieldOffset(0x40)]
public ulong ulTxRate;
}
I am looking for a one liner that transforms List<T> into object[]. It's one liner, so I am not interested in solutions such as foreach, or for...
Any takers?
Hint: No, both List<T>.ToArray() and List<T>.ToArray<object>() don't work.
Edit: Why List<T>.ToArray<object>() doesn't work? Because it can't compile.
mylist.Cast<object>().ToArray()
That will only iterate once, by the way, in case you were wondering about the performance. O(n). :)
Why? Well, because Cast<object> will use deferred execution and won't actually do anything until the list is iterated by ToArray().
List<T>.Select(x => x as object).ToArray();
Should return an object[].
If you don't have Linq (.Net 3.0) then you can use the ConvertAll() and ToArray() methods in List:
List<T> list = new List<T>();
object[] objects = list.ConvertAll<object>(item => (object)item).ToArray();
theList.Cast<object>().ToArray()
or
new List<object>(theList).ToArray()
And for a pre-LINQ solution (that only works for reference types).
(object[])List<T>.ToArray();
If you don't mind writing a very short, reusable function, the ConvertAll Extension Method might help:
http://msdn.microsoft.com/en-us/library/73fe8cwf.aspx
EDIT:
This would work too
List<int> intList = new List<int>() { 1, 3, 4 };
object[] objectList = intList.ConvertAll(item => (object)item).ToArray();
In C# on .NET 2.0 (VS 2008) the following compiles and doesn't use LINQ (as far as I can see) for reference types.
object[] oArray;
List<MyObject> oList = new List<MyObject>();
oArray = oList.ToArray();
This does not require a cast as all reference types have object as their base.
I'd suggest creating a ListCastAdapter,
Lets say you want to Convert List to List
Create implementation of
an implementation of IList that return items from a List
most likely i call it class ListCastAdapter
Have a great day
implementation (NOT TESTED):
Notice: It is recomended to make the list ReadOnly,
for the fact, now the user can insert objects that are way up the hierarchy in the original
list.
Note: CopyTo() is not implemented, you can create the same idea for the array.
using System.Collections;
using System.Collections.Generic;
namespace UDF.MyDataLayer
{
internal class ListCastAdapter<S,T> : IList<T> where T : class where S : class
{
private List<S> adaptee;
public ListCastAdapter(List<S> adaptee )
{
this.adaptee = adaptee;
}
#region Implementation of IEnumerable
public class EnumeratorCastAdapter : IEnumerator<T>
{
private IEnumerator<S> adaptee;
public EnumeratorCastAdapter(IEnumerator<S> adaptee)
{
this.adaptee = adaptee;
}
#region Implementation of IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
adaptee.Dispose();
}
#endregion
#region Implementation of IEnumerator
/// <summary>
/// Advances the enumerator to the next element of the collection.
/// </summary>
/// <returns>
/// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
/// </returns>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
public bool MoveNext()
{
return adaptee.MoveNext();
}
/// <summary>
/// Sets the enumerator to its initial position, which is before the first element in the collection.
/// </summary>
/// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority>
public void Reset()
{
adaptee.Reset();
}
/// <summary>
/// Gets the element in the collection at the current position of the enumerator.
/// </summary>
/// <returns>
/// The element in the collection at the current position of the enumerator.
/// </returns>
public T Current
{
get
{
// needs to check if it is an Object or Value Type
return adaptee.Current as T;
}
}
/// <summary>
/// Gets the current element in the collection.
/// </summary>
/// <returns>
/// The current element in the collection.
/// </returns>
/// <exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element.</exception><filterpriority>2</filterpriority>
object IEnumerator.Current
{
get { return Current; }
}
#endregion
}
/// <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 new EnumeratorCastAdapter(adaptee.GetEnumerator());
}
/// <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 adaptee.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)
{
adaptee.Add(item as S);
}
/// <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()
{
adaptee.Clear();
}
/// <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)
{
return adaptee.Contains(item as S);
}
/// <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"><paramref name="array"/> is multidimensional.-or-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"/>.-or-Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
{
throw new System.NotImplementedException("Not Needed by Me, implement ArrayCastAdapter if needed");
}
/// <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)
{
adaptee.Remove(item as S);
}
/// <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 { return adaptee.Count; }
}
/// <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
{
return true; // change, to live on the edge
}
}
#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 adaptee.IndexOf(item as S);
}
/// <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)
{
adaptee.Insert(index, item as S);
}
/// <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)
{
adaptee.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 adaptee[index] as T; }
set { adaptee[index] = value as S; }
}
#endregion
}
}