Method description from an interface [duplicate] - c#

Suppose I have this interface
public interface IFoo
{
///<summary>
/// Foo method
///</summary>
void Foo();
///<summary>
/// Bar method
///</summary>
void Bar();
///<summary>
/// Situation normal
///</summary>
void Snafu();
}
And this class
public class Foo : IFoo
{
public void Foo() { ... }
public void Bar() { ... }
public void Snafu() { ... }
}
Is there a way, or is there a tool that can let me automatically put in the comments of each member in a base class or interface?
Because I hate re-writing the same comments for each derived sub-class!

You can always use the <inheritdoc /> tag:
public class Foo : IFoo
{
/// <inheritdoc />
public void Foo() { ... }
/// <inheritdoc />
public void Bar() { ... }
/// <inheritdoc />
public void Snafu() { ... }
}
Using the cref attribute, you can even refer to an entirely different member in an entirely different class or namespace!
public class Foo
{
/// <inheritdoc cref="System.String.IndexOf" />
public void Bar() { ... } // this method will now have the documentation of System.String.IndexOf
}

Use /// <inheritdoc/> if you want inheritance. Avoid GhostDoc or anything like that.
I agree it is annoying that comments are not inherited. It would be a fairly simple add-in to create if someone had the time (i wish i did).
That said, in our code base we put XML comments on the interfaces only and add extra implementation comments to the class. This works for us as our classes are private/internal and only the interface is public. Any time we use the objects via the interfaces we have full comments display in intellisence.
GhostDoc is good start and has made the process easier to write comments. It is especially useful keeping comments up-to-date when you add/remove parameters, re-run GhostDoc and it will update the description.

GhostDoc does exactly that. For methods which aren't inherited, it tries to create a description out of the name.
FlingThing() becomes "Flings the Thing"

I would say to directly use the
/// <inheritdoc cref="YourClass.YourMethod"/> --> For methods inheritance
And
/// <inheritdoc cref="YourClass"/> --> For directly class inheritance
You have to put this comments just on the previous line of your class/method
This will get the info of your comments for example from an interface that you have documented like :
/// <summary>
/// This method is awesome!
/// </summary>
/// <param name="awesomeParam">The awesome parameter of the month!.</param>
/// <returns>A <see cref="AwesomeObject"/> that is also awesome...</returns>
AwesomeObject CreateAwesome(WhateverObject awesomeParam);

Java has this, and I use it all the time. Just do:
/**
* {#inheritDoc}
*/
And the Javadoc tool figures it out.
C# has similar marker:
<inheritDoc/>
You can read more here:
http://www.ewoodruff.us/shfbdocs/html/79897974-ffc9-4b84-91a5-e50c66a0221d.htm

Another way is to use the <see /> XML documentation tag.
This is some extra effort but works out of the box...
Here are some examples:
/// <summary>
/// Implementation of <see cref="IFoo"/>.
/// </summary>
public class Foo : IFoo
{
/// <summary>
/// See <see cref="IFoo"/>.
/// </summary>
public void Foo() { ... }
/// <summary>
/// See <see cref="IFoo.Bar"/>
/// </summary>
public void Bar() { ... }
/// <summary>
/// This implementation of <see cref="IFoo.Snafu"/> uses the a caching algorithm for performance optimization.
/// </summary>
public void Snafu() { ... }
}
Update:
I now prefer to use /// <inheritdoc/> which is now supported by ReSharper.

ReSharper has an option to copy the comments from the base class or interface.

I ended up creating a tool to post-process the XML documentation files to add support for replacing the <inheritdoc/> tag in the XML documentation files themselves. Available at www.inheritdoc.io (free version available).

Well, there is a kind of native solution, I found for .NET Core 2.2
The idea is to use <include> tag.
You can add <GenerateDocumentationFile>true</GenerateDocumentationFile> your .csproj a file.
You might have an interface:
namespace YourNamespace
{
/// <summary>
/// Represents interface for a type.
/// </summary>
public interface IType
{
/// <summary>
/// Executes an action in read access mode.
/// </summary>
void ExecuteAction();
}
}
And something that inherits from it:
using System;
namespace YourNamespace
{
/// <summary>
/// A type inherited from <see cref="IType"/> interface.
/// </summary>
public class InheritedType : IType
{
/// <include file='bin\Release\netstandard2.0\YourNamespace.xml' path='doc/members/member[#name="M:YourNamespace.IType.ExecuteAction()"]/*'/>
public void ExecuteAction() => Console.WriteLine("Action is executed.");
}
}
Ok, it is a bit scary, but it does add the expected elements to the YourNamespace.xml.
If you build Debug configuration, you can swap Release for Debug in the file attribute of include tag.
To find a correct member's name to reference just open generated Documentation.xml file.
I also assume that this approach requires a project or solution to be build at least twice (first time to create an initial XML file, and the second time to copy elements from it to itself).
The bright side is that Visual Studio validates copied elements, so it is much easier to keep documentation and code in sync with interface/base class, etc (for example names of arguments, names of type parameters, etc).
At my project, I have ended up with both <inheritdoc/> (for DocFX) and <include/> (For publishing NuGet packages and for validation at Visual Studio):
/// <inheritdoc />
/// <include file='bin\Release\netstandard2.0\Platform.Threading.xml' path='doc/members/member[#name="M:Platform.Threading.Synchronization.ISynchronization.ExecuteReadOperation(System.Action)"]/*'/>
public void ExecuteReadOperation(Action action) => action();

End the question:
This feature has been added at VS2019 v16.4.
https://developercommunity.visualstudio.com/t/608809#T-N875117
It works on the interfeace and abstruct class overrideable members

Related

How to generate documentation with references using docfx

I am trying to generate documentation for .net project (multi layer). But I am not able to see reference class information in generated documentation with docfx.
Eg:
using Microsoft.AspNetCore.Mvc;
using ServiceLayer;
namespace testApplication.Controllers
{
/// <summary>
/// Home COntroller
/// </summary>
public class HomeController : Controller
{
/// <summary>
/// Index Method
/// </summary>
/// <returns></returns>
public IActionResult Index()
{
Class1 cls1 = new Class1();
//calling testmethod.
string abc = cls1.testmethod("testing");
return View();
}
}
}
the above code is referencing ServiceLayer. using that I am calling testmethod. But Documentation is not showing, this class is using ServiceLayer Reference.
and is there any way to show comments in "//" also in the documentation
Check the following link: https://dotnet.github.io/docfx/spec/metadata_dotnet_spec.html
The metadata defined for .net include the declarations of:
Namespaces
Types, including class, struct, interface, enum, delegate
Type members, including field, property, method, event
All these are annotated with the /// XML comment. Since this is an api descriptor, it makes sense to include only those

Default the LifetimeManager to the singleton manager (ContainerControlledLifetimeManager)?

I'm using a Unity IoC container to do Dependency Injection. I designed my system around the idea that, at least for a single resolution, all types in the hierarchy would behave as singletons, that is, same type resolutions within that hierarchy would lead to the same instances.
However, I (a) would like to scan my assemblies to find types and (b) don't want to explicitly tell unity that every type is to be resolved as a singleton when registering types in the configuration file.
So, is there a way to tell unity to treat all registered mappings as singleton?
In case anyone is still looking for this... The following extension will change the default, while still allowing you to override with some other manager:
/// <summary>
/// This extension allows the changing of the default lifetime manager in unity.
/// </summary>
public class DefaultLifetimeManagerExtension<T> : UnityContainerExtension where T : LifetimeManager
{
/// <summary>
/// Handle the registering event
/// </summary>
protected override void Initialize()
{
Context.Registering += this.OnRegister;
}
/// <summary>
/// Remove the registering event
/// </summary>
public override void Remove()
{
Context.Registering -= this.OnRegister;
}
/// <summary>
/// Handle the registration event by checking for null registration
/// </summary>
private void OnRegister(object sender, RegisterEventArgs e)
{
if (e.LifetimeManager == null)
{
var lifetimeManager = (LifetimeManager)Activator.CreateInstance(typeof (T));
// Set this internal property using reflection
lifetimeManager
.GetType()
.GetProperty("InUse", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(lifetimeManager, true);
Context.Policies.Set<ILifetimePolicy>(lifetimeManager, new NamedTypeBuildKey(e.TypeTo, e.Name));
if (lifetimeManager is IDisposable)
{
Context.Lifetime.Add(lifetimeManager);
}
}
}
}
You could add a Unity extension at the 'Lifetime' stage of the resolution pipeline and in it always use a ContainerControlledLifetimeManager instance.
Edit: In fact this post has the exact example:
https://unity.codeplex.com/discussions/352179

Cant access a public variable from a public class anywhere in my solution (VS, C'#)

i have taken over a project and I am struggling to access a public variable from a public class. (Strange).
I am relatively new to C# having only done some MVC, ASP.NET stuff so i dont know if im being a bit of a clown but:
public int AlertCount
{
get { return Convert.ToInt32(alertCountTextBlock.Text); }
set { alertCountTextBlock.Text = value.ToString(); }
}
/// <summary>
/// Property which represents the number of new alerts the project currently has
/// </summary>
public int NewAlertCount
{
get { return Convert.ToInt32(newAlertCountTextBlock.Text); }
set { newAlertCountTextBlock.Text = value.ToString(); }
}
These are the two variables i am trying to access from another class inside my solution (above)
namespace Intelligence_Gathering_System.Pages.Project.Controls
{
/// <summary>
/// UserControl which acts as a selection button for each project. It displays the projects name and
/// current alert item totals along with providing methods for sharing and selecting of the project
/// </summary>
public partial class ProjectHeaderControl
{
private readonly ProjectPage _parentReference; //Reference to the controls 'parent' Project Page
/// <summary>
/// Overloaded constructor which initialises the controls members
/// </summary>
/// <param name="projectName">The name of the project</param>
/// <param name="alertCount">The total number of Alert Items in the project</param>
/// <param name="newAlertCount">The total numebr of New Alert Items in the project</param>
/// <param name="parent">A reference to the controls 'parent' Project Page</param>
public ProjectHeaderControl(string projectName, int alertCount, int newAlertCount, ProjectPage parent)
{
this is the class structure (namespace, partial class and constructor) which the variables reside,
I am simply trying to call from another piece of code (within the same solution and project ) to alter a count to increment and decrement
I have tried inside the class i need to increment and decrement (there are multiple classes i need to do this) putting the full namespace path then the variable to pinpoint it exacty and the class. variable (example of one seen below)
int x = Intelligence_Gathering_System.Pages.Project.Controls.NewAlertCount;
or
int x = ProjectHeaderControl.NewAlertCount;
neither of them are working and im a bit baffled as to why.
Am i missing something obvious here or....
Is it syntax related due to C# i'm unsure.
Any help would be appreciated.
Regards
Jordan
NewAlertCount is a property in a class - but we can't tell what that class is. (Maybe it's ProjectHeaderControl - your description is somewhat hard to understand.)
Intelligence_Gathering_System.Pages.Project.Controls is a namespace. A namespace can't declare properties.
You need to specify the class which contains the properties - and they'll either need to be static properties, or you'll need to fetch the property from an instance of the class.

What am I doing wrong with my Workflow bookmark pick trigger?

I have a NativeActivity derived activity that I wrote that is to use bookmarks as a trigger for a pick branch. Using something I found on MSDN I tried writing this to trigger the branch. The branch contains activities that fire service callbacks to remote clients via send activities. If I set a delay for the trigger, callbacks fire to the clients successfully. If I use my code activity, the pick branch activities don't fire.
public sealed class UpdateListener : NativeActivity<ClientUpdate>
{
[RequiredArgument]
public InArgument<string> BookmarkName { get; set; }
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(BookmarkName.Get(context),
new BookmarkCallback(this.OnResumeBookmark));
}
protected override bool CanInduceIdle
{
get { return true; }
}
public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj )
{
Result.Set(context, (ClientUpdate)obj);
}
}
So it takes an arg to set the bookmark name for future bookmark references to execute the trigger. OnResumeBoookmark() takes in a ClientUpdate object that is passed by my application that is hosting the workflowapp. The activity is to return the object so the ClientUpdate can be passed to the workflow and have it sent to the remote clients via the send activity in the pick branch. In theory anyways.
For some reason it seems to be correct but feels wrong. I'm not sure if I should write the Activity in a different way to take care of what I need for my WF service.
I think your intentions would be a bit clearer if you created an extension (that implements IWorkflowInstanceExtension) to perform your action here.
For example:
public sealed class AsyncWorkExtension
: IWorkflowInstanceExtension
{
// only one extension per workflow
private WorkflowInstanceProxy _proxy;
private Bookmark _lastBookmark;
/// <summary>
/// Request the extension does some work for an activity
/// during which the activity will idle the workflow
/// </summary>
/// <param name="toResumeMe"></param>
public void DoWork(Bookmark toResumeMe)
{
_lastBookmark = toResumeMe;
// imagine I kick off some async op here
// when complete system calls WorkCompleted below
// NOTE: you CANNOT block here or you block the WF!
}
/// <summary>
/// Called by the system when long-running work is complete
/// </summary>
/// <param name="result"></param>
internal void WorkCompleted(object result)
{
//NOT good practice! example only
//this leaks resources search APM for details
_proxy.BeginResumeBookmark(_lastBookmark, result, null, null);
}
/// <summary>
/// When implemented, returns any additional extensions
/// the implementing class requires.
/// </summary>
/// <returns>
/// A collection of additional workflow extensions.
/// </returns>
IEnumerable<object> IWorkflowInstanceExtension
.GetAdditionalExtensions()
{
return new object[0];
}
/// <summary>
/// Sets the specified target
/// <see cref="WorkflowInstanceProxy"/>.
/// </summary>
/// <param name="instance">The target workflow instance to set.</param>
void IWorkflowInstanceExtension
.SetInstance(WorkflowInstanceProxy instance)
{
_proxy = instance;
}
}
Within the Activity, you'd use this thusly:
var ext = context.GetExtension<AsyncWorkExtension>();
var bookmark = context.CreateBookmark(BookmarkCallback);
ext.DoWork(bookmark);
return;
This way is much more explicit (instead of using the bookmark name to convey meaning to the "outside" world) and is much easier to extend if, say, you require to send out more information than a bookmark name.
Is there something actually resuming the bookmark here? If not the workflow will wait very patiently and nothing will happen.

Trace PRISM / CAL events (best practice?)

Ok,
this question is for people with either a deep knowledge of PRISM or some magic skills I just lack (yet). The Background is simple: Prism allows the declaration of events to which the user can subscribe or publish. In code this looks like this:
_eventAggregator.GetEvent<LayoutChangedEvent>().Subscribe(UpdateUi, true);
_eventAggregator.GetEvent<LayoutChangedEvent>().Publish("Some argument");
Now this is nice, especially because these events are strongly typed, and the declaration is a piece of cake:
public class LayoutChangedEvent : CompositePresentationEvent<string>
{
}
But now comes the hard part: I want to trace events in some way. I had the idea to subscribe using a lambda expression calling a simple log message. Worked perfectly in WPF, but in Silverlight there is some method access error (took me some time to figure out the reason).. If you want to see for yourself, try this in Silverlight:
eA.GetEvent<VideoStartedEvent>().Subscribe(obj => TraceEvent(obj, "vSe", log));
If this would be possible, I would be happy, because I could easily trace all events using a single line to subscribe. But it does not... The alternative approach is writing a different functions for each event, and assign this function to the events. Why different functions? Well, I need to know WHICH event was published. If I use the same function for two different events I only get the payload as argument. I have now way to figure out which event caused the tracing message.
I tried:
using Reflection to get the causing event (not working)
using a constructor in the event to enable each event to trace itself (not allowed)
Any other ideas?
Chris
PS: Writing this text took me most likely longer than writing 20 functions for my 20 events, but I refuse to give up :-) I just had the idea to use postsharp, that would most likely work (although I am not sure, perhaps I end up having only information about the base class).. Tricky and so unimportant topic...
Probably the easiest thing would be to subclass CompositePresentationEvent and override the behavior of the Publish event. Here's the source for CompositePresentationEvent:
http://compositewpf.codeplex.com/SourceControl/changeset/view/26112#496659
Here's the current Publish behavior:
public virtual void Publish(TPayload payload)
{
base.InternalPublish(payload);
}
So you could just add a little to this:
public virtual override void Publish(TPayload payload)
{
ILoggerFacade logger = ServiceLocator.Current.GetInstance<ILoggerFacade>();
logger.Log("Publishing " + payload.ToString(), Category.Debug, Priority.Low);
base.InternalPublish(payload);
}
Here I'm using the logger facility built into Prism, but feel free to substitute your own (or better, just implement ILoggerFacade!).
I was surprised that there were any default messages being published or places to plug in tracing in this system... as much as EventAggregator is abused by people, you'd think this would be a big request!
A little late but better late than never! I recently had the same problem and this is how I solved it.
First, I didn't like the Prism method of publishing/subscribing to events, so I used a method like this instead:
http://neverindoubtnet.blogspot.com/2009/07/simplify-prism-event-aggregator.html
This post above suggests using Extension methods on Event Aggregator to simplify the call to publish/subscribe. As a result your client code looks like this:
IEventAggregator ev;
ev.Publish<MyCustomMessage>();
//or
ev.Publish(new MyCustomMessage(someData));
//and similarly subscription
ev.Subscribe<MyCustomMessage(this.OnCustomMessageReceived);
// ...
private void OnCustomMessageReceived(MyCustomMessage message)
{
// ...
}
// With a BaseMessageEvent class as follows (see the blog post above for where this comes from)
/// <summary>
/// Base class for all messages (events)
/// </summary>
/// <typeparam name="TMessage">The message type (payload delivered to subscribers)</typeparam>
public class BaseEventMessage<TMessage> : CompositePresentationEvent<TMessage>
{
}
Ok this is great, but rather than hacky extension methods I implemented my own event service as follows:
/// <summary>
/// The EventService instance
/// </summary>
public class EventService : IEventService
{
private readonly IEventAggregator eventAggregator;
private readonly ILoggerFacade logger;
/// <summary>
/// Initializes a new instance of the <see cref="EventService"/> class.
/// </summary>
/// <param name="logger">The logger instance.</param>
/// <param name="eventAggregator">The event aggregator instance.</param>
public EventService(IEventAggregator eventAggregator, ILoggerFacade logger)
{
this.logger = logger;
this.eventAggregator = eventAggregator;
}
#region IEventService Members
/// <summary>
/// Publishes the event of type TMessageType to all subscribers
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
public void Publish<TMessageType>() where TMessageType : BaseEventMessage<TMessageType>, new()
{
TMessageType message = Activator.CreateInstance<TMessageType>();
this.Publish(message);
}
/// <summary>
/// Publishes the event of type TMessageType to all subscribers
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
/// <param name="message">The message to publish</param>
public void Publish<TMessageType>(TMessageType message) where TMessageType : BaseEventMessage<TMessageType>, new()
{
// Here we can log our message publications
if (this.logger != null)
{
// logger.log etc..
}
this.eventAggregator.GetEvent<TMessageType>().Publish(message);
}
/// <summary>
/// Subscribes to the event of type TMessage
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
/// <param name="action">The action to execute when the event is raised</param>
public void Subscribe<TMessageType>(Action<TMessageType> action) where TMessageType : BaseEventMessage<TMessageType>, new()
{
// Here we can log our message publications
if (this.logger != null)
{
// logger.log etc..
}
this.eventAggregator.GetEvent<TMessageType>().Subscribe(action);
}
#endregion
}
Then I register IEventService/EventService as a singleton in the bootstrapper and forget about using the IEventAggregator, just use this (however if someone uses the IEventAggregator, its the same instance as that used by the EventService so will still work).
Finally, another trick to add is to use the Stack Frame to tell me where publications and subscriptions are coming from. Note this is a slow process (unwinding the stack frame) so use it sparingly. If you are
raising an event regularly then perhaps put a flag in your BaseEventMessage and check that to see whether to log publications for certain event types.
// Inside Publish method ... Log the subscription
if (this.logger != null)
{
Type messageType = typeof(TMessageType);
Type callingType = GetCallingType();
string methodName = GetCallingMethod().Name;
// Log the publication of this event
this.logger.Log(
string.Format("Event {0} was published by {1}.{2}()",
messageType.Name,
callingType.Name,
methodName),
Category.Debug,
Priority.Low));
}
// Additional methods to add to EventService to get the calling type/class
//
/// <summary>
/// Gets the Type that called the method or property where GetCallingType is called
/// </summary>
/// <returns>The class type that called</returns>
[MethodImplAttribute(MethodImplOptions.NoInlining)]
public static Type GetCallingType()
{
int skip = 2;
MethodBase method = new StackFrame(skip, false).GetMethod();
return method.DeclaringType;
}
/// <summary>
/// Gets the Method that called the method or property where GetCallingMethod is called
/// </summary>
/// <returns>The method type that was called</returns>
public static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
Note the above won't work in Silverlight (the use of the StackFrame), but the rest does. I've found this invaluable when debugging the multitude of events flying around a Prism app!

Categories