I'm using VS2019 16.1.1 (in VS2017 15.9.12 this does not happen)
I have method with this definition:
public static bool HasValue<T>(this T? source) where T : struct
and in a xml doc I have this:
/// <summary>
/// Internally uses <see cref="TypeValidations.HasValue{T}(T?)"/>.
/// </summary>
In VS2019 this fires the error:
Error CS1580 Invalid type for parameter T? in XML comment cref attribute: 'TypeValidations.HasValue{T}(T?)'
If I change the documentation to TypeValidations.HasValue{T}(Nullable{T}) now I got an analyzer error (SA1125) telling me that I should use the shorthand notation for nullable types.
Is there a "standard" way to refer to nullable types in the XML documentation that not generate an error in the analyzers or the compiler?
Edit:
repo code
Related
I just wondered how the StringBuffer's concrete code is look like.
But I can only find abstract method like this. Well...
Could you please let me know how to get to the concrete code ? Thanks!
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.core;
class StringBuffer implements StringSink {
/// Creates a string buffer containing the provided [content].
external StringBuffer([Object content = ""]);
/// Returns the length of the content that has been accumulated so far.
/// This is a constant-time operation.
external int get length;
/// Returns whether the buffer is empty. This is a constant-time operation.
bool get isEmpty => length == 0;
/// Returns whether the buffer is not empty. This is a constant-time
/// operation.
bool get isNotEmpty => !isEmpty;
/// Adds the string representation of [object] to the buffer.
external void write(Object? object);
/// Adds the string representation of [charCode] to the buffer.
///
/// Equivalent to `write(String.fromCharCode(charCode))`.
external void writeCharCode(int charCode);
/// Writes all [objects] separated by [separator].
///
/// Writes each individual object in [objects] in iteration order,
/// and writes [separator] between any two objects.
external void writeAll(Iterable<dynamic> objects, [String separator = ""]);
external void writeln([Object? obj = ""]);
/// Clears the string buffer.
external void clear();
/// Returns the contents of buffer as a single string.
external String toString();
}
It depends on what target platform you are interested in which is also the reason why the do this since the external function can point to different implementation depending on target.
The implementation for the different platforms can be found here:
https://github.com/dart-lang/sdk/tree/2.18.1/sdk/lib/_internal
So if you want to see the implementation used when running the Dart VM or compiled to AOT binary, the implementation of StringBuffer can be found here:
https://github.com/dart-lang/sdk/blob/2.18.1/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
Another point here is that Dart VM code often have stuff like the following which you can see in the bottom of the StringBuffer implementation:
#pragma("vm:external-name", "StringBuffer_createStringFromUint16Array")
external static String _create(Uint16List buffer, int length, bool isLatin1);
This means that we do a call to the C++ code in the Dart runtime (which is bundled together with your compiled app). So the _create call will end up calling the following method:
https://github.com/dart-lang/sdk/blob/2.18.1/runtime/lib/string.cc#L516-L534
If your target are instead JavaScript, the code used for that implementation (when compiled to a release ready JS bundle) can be found here:
https://github.com/dart-lang/sdk/blob/2.18.1/sdk/lib/_internal/js_runtime/lib/core_patch.dart#L632
I am using serilog with the sinks File and RollingFile in a crosscutting dll that delivers a logging service. I am configuring with the Appsettings nuget, therefore I have no static dependency to the mentioned sinks. However I do need them at runtime and they are not copied to the bin folder of the application, only to the bin folder of the dll. That means I get a Runtime Exception because the sink-dlls are not there. Is there a way to fix that? My workaround is creating a Variable of type RollingFileSink that I never use. But it is kind of ugly. UPDATE: that solution does not work in Release btw.
I had this issue before with Serilog, and the way I resolved it was to create a static reference to a type inside the assemblies I needed, via an assembly-level attribute that I declare inside the AssemblyInfo.cs of my main project.
Something like this:
[assembly: ImplicitDependency(typeof(Serilog.Sinks.RollingFile.RollingFileSink))]
[assembly: ImplicitDependency(typeof(Serilog.Sinks.File.PeriodicFlushToDiskSink))]
// etc...
And this is the attribute I created inside my project...
/// <summary>
/// Indicates that the marked assembly depends on the type that is specified in the constructor.
/// Typically used to force a compile-time dependency to the assembly that contains the type.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class ImplicitDependencyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ImplicitDependencyAttribute"/> class.
/// </summary>
/// <param name="dependencyType">A type from the assembly that is used dynamically.</param>
public ImplicitDependencyAttribute(Type dependencyType)
{
DependencyType = dependencyType;
}
/// <summary>
/// Gets the dependent type reference.
/// </summary>
/// <value>The dependent type reference.</value>
public Type DependencyType { get; private set; }
}
F# extension methods can be defined on types with the same name and type signature as existing instance and static methods to effectively override the default implementation of these methods, however I can't get this to work on static properties.
In particular, I'm trying to create an extension method for DateTime that returns a more precise time as follows:
#nowarn "51"
open System
module DateTimeExtensions =
open System.Runtime.InteropServices
[<DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)>]
extern void private GetSystemTimePreciseAsFileTime(int64*)
type System.DateTime with
// example showing that static methods can be overridden
static member IsLeapYear(_: DateTime) =
printfn "Using overridden IsLeapYear!"
true
// more accurate UtcNow method (note: not supported by older OS versions)
static member UtcNow =
printfn "Using overridden UtcNow!"
let mutable fileTime = 0L
GetSystemTimePreciseAsFileTime(&&fileTime)
DateTime.FromFileTimeUtc(fileTime)
However, the output when executing
open DateTimeExtensions
let _ = DateTime.IsLeapYear(DateTime.UtcNow)
is just
Using overridden IsLeapYear!
which shows that the static method 'override' is working, but not the static property.
(Note: I'm using F# 4.0)
This statement seems to be incorrect:
F# extension methods can be defined on types with the same name and
type signature as existing instance and static methods to effectively
override the default implementation of these methods, however I can't
get this to work on static properties.
No, they don't override.
You might be confused because in fact your signature of IsLeapYear is wrong, it should take an integer, that's why it works I mean you are not overriding anything, just adding a new (extension) method.
If you try it with the original signature you'll see that it doesn't work either:
type System.DateTime with
// example showing that static methods can NOT be overridden
static member IsLeapYear(_: int) =
printfn "Using overridden IsLeapYear!"
false
> DateTime.IsLeapYear(2000);;
val it : bool = true
Which is consistent with the behavior of the static property extension.
Anyway I'm not sure why it was decided not to override, if there was such decision at all when designing the language. I think it would be an interesting feature and if there is a good reason not to implement it at least it should emit a warning saying that since the method already exists it will never be called.
Maybe I will open an issue or a suggestion for the F# compiler.
I have a storage queue to which I post messages constructed using the CloudQueueMessage(byte[]) constructor. I then tried to process the messages in a webjob function with the following signature:
public static void ConsolidateDomainAuditItem([QueueTrigger("foo")] CloudQueueMessage msg)
I get a consistent failure with exception
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Program.ConsolidateDomainAuditItem ---> System.InvalidOperationException: Exception binding parameter 'msg' ---> System.Text.DecoderFallbackException: Unable to translate bytes [FF] at index -1 from specified code page to Unicode.
at System.Text.DecoderExceptionFallbackBuffer.Throw(Byte[] bytesUnknown, Int32 index)
at System.Text.DecoderExceptionFallbackBuffer.Fallback(Byte[] bytesUnknown, Int32 index)
at System.Text.DecoderFallbackBuffer.InternalFallback(Byte[] bytes, Byte* pBytes)
at System.Text.UTF8Encoding.GetCharCount(Byte* bytes, Int32 count, DecoderNLS baseDecoder)
at System.String.CreateStringFromEncoding(Byte* bytes, Int32 byteLength, Encoding encoding)
at System.Text.UTF8Encoding.GetString(Byte[] bytes, Int32 index, Int32 count)
at Microsoft.WindowsAzure.Storage.Queue.CloudQueueMessage.get_AsString()
at Microsoft.Azure.WebJobs.Host.Storage.Queue.StorageQueueMessage.get_AsString()
at Microsoft.Azure.WebJobs.Host.Queues.Triggers.UserTypeArgumentBindingProvider.UserTypeArgumentBinding.BindAsync(IStorageQueueMessage value, ValueBindingContext context)
at Microsoft.Azure.WebJobs.Host.Queues.Triggers.QueueTriggerBinding.<BindAsync>d__0.MoveNext()
Looking at the code of UserTypeArgumentBindingProvider.BindAsync, it clearly expects to be passed a message whose body is a JSON object. And the UserType... of the name also implies that it expects to bind a POCO.
Yet the MSDN article How to use Azure queue storage with the WebJobs SDK clearly states that
You can use QueueTrigger with the following types:
string
A POCO type serialized as JSON
byte[]
CloudQueueMessage
So why is it not binding to my message?
The WebJobs SDK parameter binding relies heavily on magic parameter names. Although [QueueTrigger(...)] string seems to permit any parameter name (and the MSDN article includes as examples logMessage, inputText, queueMessage, blobName), [QueueTrigger(...)] CloudQueueMessage requires that the parameter be named message. Changing the name of the parameter from msg to message fixes the binding.
Unfortunately, I'm not aware of any documentation which states this explicitly.
Try this instead:
public static void ConsolidateDomainAuditItem([QueueTrigger("foo")] byte[] message)
CloudQueueMessage is a wrapper, usually the bindings get rid of the wrapper and allow you to deal with the content instead.
In a C# class with a single constructor, I can add class summary XML documentation and constructor XML documentation:
///<summary>
///This class will solve all your problems
///</summary>
public class Awesome
{
/// <summary>
/// Initializes a new instance of the <see cref="Awesome"/> class.
/// </summary>
/// <param name="sauce">The secret sauce.</param>
public Awesome(string sauce)
{
//...implementation elided for security purposes
}
}
How do I do the same with the equivalent F# class such that the generated documentation is the same?
type Awesome(sauce: string) =
//...implementation elided for security purposes
CLARIFICATION: I'm aware that the standard XML documentation tags can be used in F#. My question is how to add them to the above snippet so that both the type and the constructor are documented.
I looked at the source of the open-source F# compiler and I think Dr_Asik is right - there is no way of documenting the implicit constructor with an XML comment. The node that represents the implicit constructor in the AST (See ImplicitCtor in ast.fs here) does not include a field for stroing the XML documentation (represented as PreXmlDoc type).
You can still document all public API - you'd have to use the method that Dr_Asik mentioned and mark the implicit constructor as private. I agree this is a bit ugly, but I think it is more convenient than not using implicit constructors:
type MyType private(a:int, u:unit) =
/// <summary>Creates MyType</summary>
/// <param name="a">Parameter A</param>
new(a:int) = MyType(a, ())
I added a dummy parameter u to the implicit constructor, so that it can be called from the public constructor. Anyway, I think this should be considered as a language bug and so I'd suggest reporting this to fsbugs at microsoft dot com.
As an aside, I think the XML documentation is mainly useful as a source of data for IntelliSense (which still needs documentation for the constructor, though) and I created some alternative F# tools that let you create tutorials and documentation by writing an F# script file with special comments using Markdown (there is a blog post about it) - so you may consider that as a useful addition to the standard XML tooling.
In exactly the same way as you do in C#: http://msdn.microsoft.com/en-us/library/dd233217.aspx
If you don't put any tags, F# assumes it is "summary":
/// This is the documentation
type MyType() = ....
... is equivalent to
/// <summary>This is the documentation</summary>
type MyType() = ...
If you want to document a constructor, you'll have to declare it explicitely. AFAIK there is no way to document the primary constructor.
/// [Type summary goes here]
type MyType(a : int) =
let m_a = a
/// [Parameterless constructor documentation here]
new() = MyType(0)
There is no way to document the implicit constructor with an XML comment inside an F# source file (.fs). One workaround is to declare the constructor explicitly (see Dr Asik's answer). Another is to put your XML comments into an F# Signature File (.fsi).
File.fs:
module File
type Awesome(sauce: string) =
member x.Sauce = sauce
File.fsi
module File
type Awesome =
class
/// Implicit constructor summary for the Awesome type
new : sauce:string -> Awesome
member Sauce : string
end
The XML documentation for this assembly will now contain the correct summary:
<member name="M:File.Awesome.#ctor(System.String)">
<summary>
Implicit constructor summary for the Awesome type
</summary>
</member>
This really is an annoying problem.
Another solution I ended up using is to not rely on a primary constructor:
/// Documentation type.
type Awesome =
val sauce : string
/// <summary>Documentation constructor.</summary>
/// <param name="sauce">Sauce. Lots of it.</param>
new (sauce) = { sauce = sauce }
More verbose, but no extra files or private constructors needed...