As the name states, I have no idea how to reference a dictionary indexer. Any help here? :)
FYI, I've tried:
<see cref="Item"/>
<see cref="Item(Int32)"/> //Highly doubted this would work.
<see cref="Item(TKey)"/>
<see cref="Item[TKey]"/>
You can use the full property syntax to reference indexers:
namespace ConsoleApplication1
{
/// <summary>
/// See indexer <see cref="P:ConsoleApplication1.MyDictionary`2.Item(`0)"/>
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class MyDictionary<TKey, TValue>
{
/// <summary>
/// Indexer
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public TValue this[TKey key]
{
get { return default(TValue); }
set { }
}
}
}
You can check that the property was resolved properly by inspecting the generated XML file:
<doc>
<assembly>
<name>ConsoleApplication1</name>
</assembly>
<members>
<member name="T:ConsoleApplication1.MyDictionary`2">
<summary>
See <see cref="P:ConsoleApplication1.MyDictionary`2.Item(`0)"/>
</summary>
<typeparam name="TKey"></typeparam>
<typeparam name="TValue"></typeparam>
</member>
<member name="P:ConsoleApplication1.MyDictionary`2.Item(`0)">
<summary>
Indexer
</summary>
<param name="key"></param>
<returns></returns>
</member>
</members>
</doc>
Notice how the first P: matches the second one.
Finally, make sure it's working with Intellisense:
Update by Original Poster (myermian):
I did a little bit of digging and have discovered that the shortform of an indexer property is just "this". Ex: <see cref="this"/>
Try <see cref="P:Item(System.Int32)" /> (the name is Item, not Items)
Related
I'm using XML tags to document my program so I can see descriptions when I hover over my classes, methods, and such. I want to display a list on one of my classes like so:
/// <remarks>
/// <b>List of methods below</b>
/// <list type="table">
/// <listheader>
/// <term>
/// <see cref="MyMethod()"/>
/// </term>
/// <description>
/// <inheritdoc cref="MyMethod()"/>
/// </description>
/// </listheader>
/// </list>
/// </remarks>
public class MyClass
{
/// <summary>
/// Description of MyMethod()
/// </summary>
public void MyMethod()
{
// Do something
}
}
The problem is that <inheritdoc /> is not loading anything in the preview. However, When I move <inheritdoc /> outside of the <list>, with the exact same formatting, it displays perfectly. Is there any way to reference the description of MyMethod() within the list?
<inheritdoc> by default includes all members in the target XML comments. If you need the <summary> you need to select it using the path attribute:
<inheritdoc cref="MyMethod" path='//summary/text()'/>
It should render something like this:
I have made a school project that my teacher will check later on.
I am trying to add some Documentation Comments in Visual Studio Code with the help of a plugin that allows me to write /// which makes the xml code automatically.
I have read from the Microsoft Docs about XML Documentation that you can make a seperate XML file rather than clutter the code with comments but i have been having a hard time getting it to work.
Here is an example:
///<include file='docs.xml' path='docs/members[#name="program"]/Select/*'/>
public static bool Select (ConsoleKey input) {
ConsoleKeyInfo key = Console.ReadKey (true);
if (key.Key == input) {
return true;
}
return false;
}
This is what the doc.xml file has about this method:
<doc>
<members name="program">
<Select>
<summary>
Summarizes a way to detect <paramref name ="input"/>.
</summary>
<returns>
true when <paramref name = "input"/> is detected.
</returns>
<param name="input"> Checks what key it should detect.</param>
<example>
<code>
string outputToConsole = "Hello World!";
void Main () {
if (Selecting.Select (ConsoleKey.Spacebar)) {
Console.WriteLine (outputToConsole);
//Prints "Hello World" when key "Spacebar" is pressed!
}
}
</code>
</example>
</Select>
It currently does not work (It does not show a description on the method at all) and i have been racking my head over this.
The documentation says (emphasis mine):
This is an alternative to placing documentation comments directly in your source code file. By putting the documentation in a separate file, you can apply source control to the documentation separately from the source code. One person can have the source code file checked out and someone else can have the documentation file checked out.
I do understand the motivation behind this, but if you decide to use a separate file you can no longer use Visual Studio autocomplete/intellisense to generate the XML elements for you, and you'll need to learn the schema/syntax of the XML documentation file.
Also, as the assembly gets bigger, so will the XML file. In the real world this file could have 1000s of lines of code. From a maintenance and source control perspective, I'd rather have the documentation in the c# source files. I honestly think it's not worth the trouble.
Anyway, if you still want to use the external files there are a few tricks you can use.
Consider a class library named FileDemo. Righ-click the project > Properties > Build and then tick the checkbox XML Documentation File:
This will generate the XML documentation file on build:
And now the funny part. As I mentioned before, the XML documentation file has a particular syntax you'll need to learn. The best way to do it is to add some XML documentation to existing classes, methods etc and check the generated XML. For example, considering the following namespaces and classes:
namespace FileDemo
namespace FileDemo
{
/// <summary>
/// This is a class
/// </summary>
public class Class1
{
/// <summary>
/// Does nothing
/// </summary>
/// <param name="text">Just some text</param>
public void DoNothing(string text)
{
}
}
/// <summary>
/// This is another class
/// </summary>
public class Class2
{
/// <summary>
/// Bla bla
/// </summary>
/// <param name="text">Just some text</param>
public void DoSomething(string text)
{
}
}
}
namespace FileDemo.AnotherNamespace
namespace FileDemo.AnotherNamespace
{
/// <summary>
/// Yet another class
/// </summary>
public class Class3
{
/// <summary>
/// Gets or sets something
/// </summary>
public string Foo { get; set; }
/// <summary>
/// Creates a new instance of <see cref="Class3"/>
/// </summary>
public Class3()
{
}
/// <summary>
/// This method is supposed to calculate something
/// </summary>
/// <param name="firstValue">First value</param>
/// <param name="secondValue">Second value</param>
/// <returns>The result of the calculation</returns>
public int Calculate(int firstValue, int secondValue)
{
return 1;
}
}
}
After building the project, the generated documentation file is the following:
<?xml version="1.0"?>
<doc>
<assembly>
<name>FileDemo</name>
</assembly>
<members>
<member name="T:FileDemo.AnotherNamespace.Class3">
<summary>
Yet another class
</summary>
</member>
<member name="P:FileDemo.AnotherNamespace.Class3.Foo">
<summary>
Gets or sets something
</summary>
</member>
<member name="M:FileDemo.AnotherNamespace.Class3.#ctor">
<summary>
Creates a new instance of <see cref="T:FileDemo.AnotherNamespace.Class3"/>
</summary>
</member>
<member name="M:FileDemo.AnotherNamespace.Class3.Calculate(System.Int32,System.Int32)">
<summary>
This method is supposed to calculate something
</summary>
<param name="firstValue">First value</param>
<param name="secondValue">Second value</param>
<returns>The result of the calculation</returns>
</member>
<member name="T:FileDemo.Class1">
<summary>
This is a class
</summary>
</member>
<member name="M:FileDemo.Class1.DoNothing(System.String)">
<summary>
Does nothing
</summary>
<param name="text">Just some text</param>
</member>
<member name="T:FileDemo.Class2">
<summary>
This is another class
</summary>
</member>
<member name="M:FileDemo.Class2.DoSomething(System.String)">
<summary>
Bla bla
</summary>
<param name="text">Just some text</param>
</member>
</members>
</doc>
As you can see, there is a particular schema/syntax that you need to learn for each element you're trying to document (classes, methods, properties, constructors, parameters, return types, etc).
When specifying summary tag comments, is there a way with the <param> tag to note that a parameter is optional, ie. the client can supply a value or null, such as: <param name="Mime" optional="true">.
Googling has failed to provide me with a set list of attributes or allowed values.
/// <summary>
/// Sets data associated with instance
/// </summary>
/// <param name="Key">The key defining the data</param>
/// <param name="Value">The data</param>
/// <param name="Mime">The mime type of the data (optional)</param> <----- Mark as optional
Thanks
No, you can't. The only attribute being recognized by VS is the name, like that:
<param name="FileName" >The filename of the file to be loaded.</param>
The only thing that you can do - is to set xsl transform for your output document. But this won't have any effect on Intellisense.
You should provide an overload that omits the optional parameter:
/// <summary>
/// Sets data associated with the instance using the default media type.
/// </summary>
/// <param name="key">The key defining the data.</param>
/// <param name="value">The data.</param>
public void SetData(object key, object value)
{
SetData(key, value, null);
}
/// <summary>
/// Sets data associated with the instance using the specified media type.
/// </summary>
/// <param name="key">The key defining the data.</param>
/// <param name="value">The data.</param>
/// <param name="mime">The media type of the data.</param>
public void SetData(object key, object value, string mime)
{
...
}
Alternatively, you can declare the parameter as optional:
/// <summary>
/// Sets data associated with the instance.
/// </summary>
/// <param name="key">The key defining the data.</param>
/// <param name="value">The data.</param>
/// <param name="mime">The media type of the data.</param>
public void SetData(object key, object value, string mime = null)
{
...
}
You can use <remarks></remarks> tag. Doesn't exist special tag for optional params.
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
}
}
<see cref="switch" />, for example, doesn't work - I get the compilation warning: XML comment on ... has syntactically incorrect cref attribute 'switch'
Context for those who are interested...
/// <summary>Provides base functionality for hand-coded abstractions of API method wrappers, mostly those that abstract over
/// parameters that are required to be JSON-encoded.</summary>
public class FacebookArgs : Dictionary<String, Object>
{
/// <summary>Initializes an instance of <see cref="FacebookArgs" />.</summary>
public FacebookArgs() { }
/// <summary>Intializes an instance of <see cref="FacebookArgs" />, that contains elements copied from <paramref name="dictionary "/>.</summary>
/// <param name="dictionary"></param>
public FacebookArgs(IDictionary<String, Object> dictionary)
: base(dictionary) { }
/// <summary>Gets or sets the value associated with the specified key.</summary>
/// <param name="key">The key of the value to get or set.</param>
/// <returns>The value associated with the specified key.</returns>
/// <remarks>This implementation hides the base indexer implementation such that specifying a key that does not exist returns null rather than throwing a <see cref="KeyNotFoundException" />.</remarks>
public new Object this[String key]
{
get
{
Object value;
if (this.TryGetValue(key, out value)) return value;
else return null;
}
set { base[key] = value; }
}
/// <summary>In derived classes, provides specialized serialization logic for specific properties contained in this object.</summary>
/// <param name="key">The key of the property to serialize.</param>
/// <param name="args">A reference to a dictionary of arguments that will be passed directly to a <see cref="FacebookRequest" /> object.</param>
/// <remarks>
/// <para>This method allows specialized serialization logic, such as JSON encoding, to be applied to specific properties.</para>
/// <para>To implement, use a <c>switch</c> (<c>Select</c> in VB.NET) statement to filter based on <paramref name="key" /> and provide the property-specific logic.
/// The resulting value should then be added to <paramref name="args" /> using the same <paramref name="key "/>.
/// </para>
/// <para>Properties that do not require additional processing (strings, integral values, etc) should be ignored.</para>
/// </remarks>
protected virtual void SerializeProperty(String key, ref IDictionary<String, Object> args) { }
/// <summary>Returns a dictionary of key/value pairs suitable to be passed a <see cref="FacebookRequest" /> object.</summary>
/// <returns>A dictionary of key/value pairs suitable to be passed a <see cref="FacebookRequest" /> object.</returns>
/// <remarks>This method calls the <see cref="SerializeProperty" /> for each key in the object, which allows property-specific processing
/// to be done on any property.</remarks>
/// <seealso cref="SerializeProperty" />
public IDictionary<String, Object> GetArgs()
{
IDictionary<String, Object> args = new Dictionary<String, Object>();
foreach (String key in this.Keys)
{
this.SerializeProperty(key, ref args);
if (!args.ContainsKey(key) && this[key] != null)
{
args.Add(key, this[key]);
}
}
return args;
}
}
The tag in question can be found in the <remarks> tag for SerializeProperty. I'm erring on the side of verbose documentation. I also plan on providing some <example>s, I just haven't gotten around to it yet.
cref is meant to refer to another member - a class, a method etc.
What would you expect it to link to in this case? In general, what do you want the overall effect to be?
According to this excellent XML doc guide, the <see> tag has an undocumented attribute langword:
<see langword="switch" />
Would that help you? It might be worth trying it just to see what it does.
If you just want to use a normal hyperlink, use href instead of cref:
<see href="http://msdn.microsoft.com/en-us/library/06tc147t.aspx">switch</see>