How do you provide xml comments/documentation for delegate parameters? - c#

given a delegate like
Func<string,string,string> MyFunc = (firstName,lastName) => string.Format("Given Name:{0} Surname:{1}",
firstName,
lastName);
How would you can you document the parameters of firstName and lastName, so they show up in intellisense (like method descriptions and parameters do)?
Example:
/// <summary>
/// My Method
/// </summary>
/// <param name="firstName">The first name.</param>
/// <param name="lastName">The last name.</param>
/// <returns></returns>
public string MyMethod(string firstName, string lastName)
{
return string.Format("Given Name:{0} Surname:{1}",firstName,lastName);
}
I want to hover over the delegate or have intellisense popup when I type and tell me the descriptions for the the delegate parameters, like it would with the above method.

A field of a delegate type is still a field and not a method—it doesn't take parameters in itself. The parameters belong to the delegate type, not the delegate field. You can write the comments for parameters when you delegate types if you want.
/// <summary>
/// Tests something.
/// </summary>
/// <param name="test">Something that's going to be tested.</param>
delegate void Test(int test);
Func<string,string,string> is a general delegate for functions with three parameters. For specific purposes, you can always declare your own delegate type that represents the abstracted method more specifically and add comments to its parameters.

Related

How to document overloaded methods with the same XML comments?

I know there are questions like this, but they're old. So I'm creating a new one.
At the moment when there are 3 overloaded methods I have to do this:
/// <summary>
/// Description that described summary of an overloaded method.
/// </summary>
/// <param name="fileName">Description that describes filename parameter</param>
/// <param name="options">Description that describes options parameter</param>
/// <returns>Description of what method returns</returns>
public bool ReadFrom(string fileName, ReaderOptions options = null) {
return false;
}
/// <summary>
/// Description that described summary of an overloaded method.
/// </summary>
/// <param name="stream">Description that describes stream parameter</param>
/// <param name="options">Description that describes options parameter</param>
/// <returns>Description of what method returns</returns>
public bool ReadFrom(Stream stream, ReaderOptions options = null) {
return false;
}
/// <summary>
/// Description that described summary of an overloaded method.
/// </summary>
/// <param name="rawData">Description that describes rawData parameter</param>
/// <param name="options">Description that describes options parameter</param>
/// <returns>Description of what method returns</returns>
public bool ReadFrom(byte[] rawData, ReaderOptions options = null) {
return false;
}
And I would like to have something like this:
#region overloadedReadFromMethods
/// <summary>
/// Description that described summary of an overloaded method.
/// </summary>
/// <param name="fileName">Description that describes filename parameter</param>
/// <param name="options">Description that describes options parameter</param>
/// <returns>Description of what method returns</returns>
public bool ReadFrom(string fileName, ReaderOptions options = null) {
return false;
}
/// <param name="stream">Description that describes stream parameter</param>
public bool ReadFrom(Stream stream, ReaderOptions options = null) {
return false;
}
/// <param name="rawData">Description that describes rawData parameter</param>
/// <returns>Even considering that returns tag is present on the first overloaded method,
/// this overloaded method shows this specific description.
/// </returns>
public bool ReadFrom(byte[] rawData, ReaderOptions options = null) {
return false;
}
#endregion overloadedReadFromMethods
So the first overloaded method describes default description and then methods below can override it with their own descriptions. I want it to show in Visual Studio's IntelliSense.
TLDR - It's not possible
Long story short, as was the case in the past, you still cannot re-use comments this way.
Some interesting ideas here
Create one function with optional parameters. While this would mitigate the problem, I find that optional parameters are sometimes incovenient themselves as they overcomplicate the logic inside and make unit testing very difficult. Overaloading in your case make sense, so this solution does not apply.
Use the <overloads> comment. I can't see it in the official documentation though
Use the <see> and <seealso> xml tag to use reference
Use the <include> tag
This is still not a solution but it allows you to have separate xml documents and handle overall. include documentation
I think the extra work to document each method is necessary because they all have different signatures. Methods have different <param></param>
InheritDoc is a package that can be used to inherit xml docs.

Add completion suggestion 'nameof' for parameter with Resharper

I would like to add a completion suggestion of nameof to a parameter in a method.
The method:
public static class Ensure
{
/// <summary>
/// throws <see cref="ArgumentException"/> exception if string is null or empty.
/// </summary>
/// <param name="value">string to check its content.</param>
/// <param name="name">name of parameter passed.</param>
public static void StringNotNullOrEmpty(string value, string name)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Value cannot be null or empty", name);
}
}
}
When typing Ensure.StringNotNullOrEmpty(testString, <...>) I would like to get the nameof(testString) suggestion for <...>. The above method doesn't suggest the nameof (Worse still, after typing 'n' I only get suggestions as null, new). The nameof(...) is necessary so I get the correct ParamName in the ArgumentException.
On the site of Resharper it says that ArgumentNullException makes use of the nameof suggestion by using the InvokerParameterNameAttribute (source: Resharper InvokerParameterNameAttribute).
Attempt:
So I installed the nuget package in my project: JetBrains.Annotations 10.4.0 and changed the method as followed:
public static class Ensure
{
/// <summary>
/// throws <see cref="ArgumentException"/> exception if string is null or empty.
/// </summary>
/// <param name="value">string to check its content.</param>
/// <param name="name">name of parameter passed.</param>
public static void StringNotNullOrEmpty([CanBeNull] string value,
[NotNull] [InvokerParameterName] string name)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Value cannot be null or empty", name);
}
}
}
Unfortunately the above attempt is still not giving me the suggestion of nameof when I've typed: Ensure.StringIsNotNullOrEmpty(testString,.
Some other thing I found was the CallerMemberNameAttribute on MSDN. But this only gives me the name of the calling method as a string.
I also looked into some repo's on GitHub, and could only find solutions the same way as my attempt.
One reason I can think of is when having two string parameters in a method with an InvokerParameterNameAttribute defined on the latter, it could be confusing for Resharper.
Is it possible to add the nameof suggestion for a parameter in a method? And how can I achieve this with the above method?
Additional info:
I have VS2015 + Resharper 2016.3.2.
actually that works (but not as you intended). it will not suggest as soon as you type ,... it will only suggest you to use nameof expression when you fully type name of argument in form of string instead of using nameof expression.
static void Caller(string arg)
{
StringNotNullOrEmpty(arg, "arg"); // only now resharper suggests to use nameof.
StringNotNullOrEmpty(arg, "something else"); // now resharper complains about unknown argument name.
}
You can submit feedback on resharper to actually implement the behavior you want.
Also if you type "" the cursor will move to middle of double quotes and resharper suggests name of available parameters.
BTW you can always comment your code that can be useful for every future readers
/// <summary>
/// throws <see cref="ArgumentException"/> exception if string is null or empty.
/// </summary>
/// <param name="value">string to check its content.</param>
/// <param name="name">name of parameter passed.</param>
public static void StringNotNullOrEmpty([CanBeNull] string value,
[NotNull] [InvokerParameterName] string name)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Value cannot be null or empty", name);
}
}

Default value for flags enum in a RESTful WCF service

WCF supports using enum types that are tagged with the FlagsAttribute as parameters within an UriTemplate. Like this:
[DataContract]
[Flags]
public enum OptionsEnum
{
[EnumMember]
None = 0,
[EnumMember]
MyOption1 = 1,
[EnumMember]
MyOption2 = 2,
[EnumMember]
MyOption3 = 4,
[EnumMember]
MyOption4 = 8
}
[ServiceContract]
public interface MyServiceContract
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "resource?options={options}")]
void MyOperation(OptionsEnum options);
}
The resource can then be requested via URLs like this:
GET /resource?options=None
GET /resource?options=MyOption1
GET /resource?options=MyOption1,MyOption3
All of this works really nicely as long the URL actually contains a value for the options parameter. However, if I request the resource without specifying a value in the URL, like this:
GET /resource
I get an exception with the message Value cannot be null.\r\nParameter name: value
and the following stack trace:
at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
at System.Enum.Parse(Type enumType, String value, Boolean ignoreCase)
at System.ServiceModel.Dispatcher.QueryStringConverter.ConvertStringToValue(String parameter, Type parameterType)
at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Obviously, this is because QueryStringConverter passes null into Enum.Parse(...) in this case. As a result the implementation of MyServiceContract will not be executed.
Of course I could just switch to string for the type of the options parameter and do all the parsing stuff myself within the service implementation, but that's not what I want, really.
Does anyone know a clean solution to have OptionsEnum.None passed into the service implementation if the URL does not contain a value (just like 0 is passed for omitted parameters of type int)?
I already tried using a custom TypeConverter implementation, but even that does not seem to work. Looking at the implementation of QueryStringConverter it seems like it will always try to convert enum types by itself.
Ok, I have found a solution that is reusable and does not involve switching to string for the type of the flags parameter. I was hoping for something simpler, though. Anyway, in case it helps someone else, here it is.
The approach is relatively simple:
Wrap the enum in a reference type.
Use a TypeConverter to customize the process of converting the value from string to our flags enum as implemented by WCF's QueryStringConverter.
/// <summary>
/// Wraps a flags enum value.
/// </summary>
/// <remarks>
/// This class is meant to be used in conjunction with
/// <see cref="FlagsConverter{TFlags,TEnum}"/> and simply boxes an enum.
/// This is necessary in order to customize WCF's default behavior for enum
/// types (as implemented by <see cref="QueryStringConverter"/>) by using a
/// <see cref="TypeConverter"/>.
/// </remarks>
/// <devdoc>
/// We prefer this over using an 1-Tuple (<see cref="Tuple{T1} "/>) as it
/// allows us to add constraints on the type parameter. Also, the value
/// wrapped by a <see cref="Tuple{T1} "/> is read-only, which we don't want
/// here, as there is no reason to prevent [OperationContract] methods from
/// writing the wrapped <see cref="Value"/>.
/// </devdoc>
/// <typeparam name="TEnum">
/// The enum type. Must be attributed with <see cref="FlagsAttribute"/>.
/// </typeparam>
public abstract class Flags<TEnum>
where TEnum : struct, IConvertible
{
// Use a static c'tor to add run-time checks on the type parameter that
// cannot be checked at compile-time via constraints.
static Flags()
{
if (!typeof(TEnum).IsEnum)
{
throw new InvalidOperationException("T is not an enum");
}
if (!typeof(TEnum).IsDefined(typeof(FlagsAttribute), false))
{
throw new InvalidOperationException("T is not a flags enum");
}
}
/// <summary>
/// The enum value.
/// </summary>
public TEnum Value
{
get;
set;
}
}
/// <summary>
/// A <see cref="TypeConverter"/> implementation that converts from
/// <c>string</c> to <see cref="Flags{TEnum}"/>.
/// </summary>
/// <remarks>
/// <para>
/// Meant to be used in conjunction with <see cref="Flags{TEnum}"/>.
/// The purpose of this <see cref="TypeConverter"/> implementation is to
/// convert both <c>null</c> and the empty string to <c>default(TEnum)</c>
/// instead of throwing an exception. This way, a flags enum (wrapped in an
/// instance of <see cref="Flags{TEnum}"/>) can be used as the type of an
/// optional parameter in a RESTful WCF <c>OperationContract</c> method.
/// </para>
/// <para>
/// If the string value (as provided by <see cref="QueryStringConverter"/>)
/// is <c>null</c> or empty or can be successfully parsed into an enum
/// value of type <typeparamref name="TEnum"/>, this implementation will
/// provide an instance of <typeparamref name="TFlags"/>. Thus, there is no
/// need to check a <typeparamref name="TFlags"/>-typed value for
/// <c>null</c> within the implementation of an <c>OperationContract</c>
/// method.
/// </para>
/// </remarks>
/// <typeparam name="TFlags">
/// A sub-class of <see cref="Flags{TEnum}"/>. Must have a default c'tor.
/// </typeparam>
/// <typeparam name="TEnum">
/// The enum type. Must be attributed with <see cref="FlagsAttribute"/>.
/// </typeparam>
public class FlagsConverter<TFlags, TEnum> : TypeConverter
where TFlags : Flags<TEnum>, new()
where TEnum : struct, IConvertible
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (string.IsNullOrEmpty((string)value))
{
// The following line is what Flags<> and FlagsConverter<,> is
// all about: Provide the enum's default value (meaning no flag
// is set) for null and the empty string instead of passing it
// into Enum.Parse() (which results in an ArgumentException).
return new TFlags { Value = default(TEnum) };
}
// Otherwise, just pass the value on the Enum.Parse(), i.e. don't
// add any further changes to WCF's default behavior as implemented
// by QueryStringConverter.
return new TFlags { Value = (TEnum)Enum.Parse(typeof(TEnum), (string)value, true) };
}
}
These two classes can now be used to solve the problem like this
(reusing the example from the original question):
[DataContract]
[Flags]
public enum OptionsEnum
{
[EnumMember]
None = 0,
[EnumMember]
MyOption1 = 1,
[EnumMember]
MyOption2 = 2,
[EnumMember]
MyOption3 = 4,
[EnumMember]
MyOption4 = 8
}
[DataContract]
[TypeConverter(typeof(FlagsConverter<MyOptionalFlags, OptionsEnum>))]
public class MyOptionalFlags
: Flags<OptionsEnum>
{
// We don't add anything here, as the whole purpose of this class is to
// wrap the OptionsEnum in a class that will be instantiated by the
// attributed FlagsConverter.
}
[ServiceContract]
public interface MyServiceContract
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "resource?options={options}")]
void MyOperation(MyOptionalFlags options);
}
public class MyServiceContractImpl
: MyServiceContract
{
public void MyOperation(MyOptionalFlags options)
{
if (options.Value == OptionsEnum.None)
{
// We will now get here for requests that do not specify a
// value for the options parameter in the URL. Note that just
// like for an enum value, we don't have to check if options is
// null here.
}
}
}

StyleCop SA1620, I don't know how to resolve my XML Comments to its liking

I have the following code w/comments: (It does compile)
/// <summary>
/// return a passing result of a particular type
/// </summary>
/// <typeparam name="T">Type of the value to be returned</typeparam>
/// <param name="value">the value to be returned</param>
/// <returns>a passing result</returns>
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
I get the following warning with it:
Warning 1 SA1620 : CSharp.Documentation :
The typeparam tags in the documentation header must
match the generic types for the method.
I did look at the help page for this error, which gives this explanation:
To fix a violation of this rule, add and fill-in one tag
for each generic type parameter on the element, and make sure that
the tags appear in the same order as the element’s type
parameters.
And it has provided sample code:
/// <summary>
/// A sample generic class.
/// </summary>
/// <typeparam name="S">The first generic type parameter.</typeparam>
/// <typeparam name="T">The second generic type parameter.</typeparam>
public class Class1<S, T>
{
}
I don't see anything about mine that breaks the standards it is showing, and I have tried various odd things, but I have no real idea of what I'm supposed to do here.
The only way that this can compile is if this method is inside a class that is generic in T. This method doesn't have any type parameters. If it was generic, there would be type parameters after the name of the method:
public static Result<T> Pass<T>(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
But that's not the case with your method. So it must be:
class SomeClass<T>
{
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
}
And any documentation about the type parameter belongs up at the class level. E.g.:
/// <summary>
/// This is a result class
/// </summary>
/// <typeparam name="T">Type of the value to be returned</typeparam>
public class Result<T>
{
public bool Passed { get; set; }
public T Value { get; set; }
/// <summary>
/// return a passing result of a particular type
/// </summary>
/// <param name="value">the value to be returned</param>
/// <returns>a passing result</returns>
public static Result<T> Pass(T value)
{
return new Result<T>()
{
Passed = true,
Value = value
};
}
}

Moles and AppSettingsReader?

I'm working with Moles to write some unit tests. I searched online but I don't see any responses on how to use Moles to intercept the calls to AppSettingsReader.GetValue.
Has anyone been able to do this using Moles? Or am I forced into isolating the calls in my own class I can inject or mock? Ideally there is a way to directly use Moles to intercept the calls because we don't really want to modify the code we're looking to put under test.
Thanks!
Firstly, I strongly recommend moving to the release version of Moles, called "Fakes and Stubs", in .NET 4.5 / C# 5 / Visual Studio 2012.
The System.Configurations namespace is incompatible with the Mole/Fake type, and must be stubbed. To create a stub using the Moles Framework, simply create an interface for the System.Configuration.AppSettingsReader type. The Moles compiler will automatically convert the interface into a Stub type.
Here's an interface you can add to your project:
using System;
namespace YOUR_NAMESPACE_HERE
{
/// <summary>
/// IOC object for stubbing System.Configuration.AppSettingsReader.
/// Provides a method for reading values of a particular type from
/// the configuration.
/// </summary>
interface IAppSettingsReader
{
/// <summary>
/// Gets the value for a specified key from the
/// System.Configuration.ConfigurationSettings.AppSettings property
/// and returns an object of the specified type containing the
/// value from the configuration.
/// </summary>
/// <param name="key">The key for which to get the value.</param>
/// <param name="type">The type of the object to return.</param>
/// <returns>The value of the specified key</returns>
/// <exception cref="System.ArgumentNullException">key is null.
/// - or -
/// type is null.</exception>
/// <exception cref="System.InvalidOperationException">key does
/// not exist in the <appSettings> configuration section.
/// - or -
/// The value in the <appSettings> configuration section
/// for key is not of type type.</exception>
public object GetValue(string key, Type type);
}
}
Here's a stub class, too:
using System;
using System.Configuration;
namespace YOUR_NAMESPACE_HERE
{
/// <summary>
/// Production stub for System.Configuration.AppSettingsReader.
/// Provides a method for reading values of a particular type from
/// the configuration.
/// </summary>
public class AppSettingsReaderStub : IAppSettingsReader
{
/// <summary>
/// Gets the value for a specified key from the
/// System.Configuration.ConfigurationSettings.AppSettings property
/// and returns an object of the specified type containing the value
/// from the configuration.
/// </summary>
/// <param name="key">The key for which to get the value.</param>
/// <param name="type">The type of the object to return.</param>
/// <returns>The value of the specified key</returns>
/// <exception cref="System.ArgumentNullException">key is null.
/// - or -
/// type is null.</exception>
/// <exception cref="System.InvalidOperationException">key does not
/// exist in the <appSettings> configuration section.
/// - or -
/// The value in the <appSettings> configuration section for
/// key is not of type type.</exception>
public object GetValue(string key, Type type)
{
var reader = new AppSettingsReader();
object result = reader.GetValue(key, type);
return result;
}
}
}

Categories