ricosuter / namotion.reflection Goto Github PK
View Code? Open in Web Editor NEW.NET library with advanced reflection APIs.
License: MIT License
.NET library with advanced reflection APIs.
License: MIT License
XML documentation placed on (abstract) base controller class does not appear in swagger doc. Only XML documentation applied to the controller class that inherits the base class appears.
[ApiController]
public abstract class BaseController : ControllerBase
{
/// <summary>
/// This documentation will not appear in swagger doc
/// </summary>
/// <param name="p">This will also not appear in swagger doc</param>
/// <returns></returns>
[HttpGet("{p}")]
public ActionResult Test(int p)
{
return Ok();
}
}
/// <summary>
/// This controller now has a Patch method and an inherited Get method
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class MyController : BaseController
{
/// <summary>
/// This documentation WILL appear in swagger doc
/// </summary>
/// <param name="p">This parameter will be documented</param>
/// <returns></returns>
[HttpPatch("{p}")]
public ActionResult Test2(int p)
{
return Ok();
}
}```
C#
.NET Core 2.2
Visual Studio 2017
NSwag 12.0.14
The method works great for blazor server but not for wasm. Added components as embedded resources but still doesn't work. Did i do something wrong?
It would be great if I could easily access the functionality behind XmlDocsExtensions.cs
/ private string GetXmlDocsPath(dynamic assembly)
.
It appears that this library which I'm assuming NJsonSchema and NSwag is now using has regressed the fix for: RicoSuter/NSwag#899
NSwag/NJsonSchema isn't outputing the xml documentation into my openapi document.
I created this classes
[Table("Left")]
public class Left
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[DisallowNull]
public virtual Child Child { get; set; } = null!;
public virtual Left? Next { get; set; }
public virtual IList<Right> Rights { get; set; } = new List<Right>();
}
[Table("Child")]
public class Child
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
}
[Table("Right")]
public class Right
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public virtual IList<Left> Lefts { get; set; } = new List<Left>();
}
And have this problem
var left1 = new Left();
left1.EnsureValidNullability();
This throw the error
If I get from the database I get no error
var optionsBuilder = new DbContextOptionsBuilder<ModelContext>().UseLazyLoadingProxies()
.UseSqlServer("Server=.\\sql2019;Database=Nullable;Trusted_Connection=false;user id=sa;pwd=sa;MultipleActiveResultSets=true;Encrypt=false");
using (var context = new ModelContext(optionsBuilder.Options))
{
var left = context.Left.Find(leftid);
if (left != null)
{
var x = left.Child;
left.GetType()?.GetProperty("Child")?.SetValue(left, null);
x = left.Child;
left.EnsureValidNullability();
}
}
Using .NET 4.8 with Namotion.Reflection v2.0.3, if I have a method with a signature like the following:
public void TestMethod(Expression<Func<TModel>> expr)
and then call GetXMLDocsSummary()
on a MethodInfo
instance for it, the call will return an empty string even when there is an appropriate entry in the XML doc file. However if I change the return of the delegate to a concrete type (e.g. Func<string>>
) the summary is returned without issue.
Stepping into the code I can see that GetMemberElementName()
is throwing a "Method may only be called on a Type for which Type.IsGenericParameter is true." exception. This occurs at the point where the code iterates the generic type arguments and references GenericParameterPosition
. The type in question (the Func
) has IsGenericParameter
as false (however its GenericTypeArguments
has a member with IsGenericParameter
true and a valid GenericParameterPosition
- perhaps an additional level of indirection is needed?)
Test case code (based on the Namotion.Reflection.Demo sample) is attached.
Commit ID: 33e53f6
Steps:
XmlDocsExtensions.GetXmlDocsSummary(...)
is called for the same member concurrentlyXmlDocsExtensions.TryGetXmlDocsDocument
adds an entry to XmlDocsExtensions.Cache
with documentation loaded into XElement. This is the first problematic place, because current implementation of TryGetXmlDocsDocument
can return different results for the same key. Be result immutable or if every client got own unique result, then there will be no race condition.The following snippet will fail with an exception thrown by Linq implementation:
public interface IMyObject
{
/// <summary>
/// Description
/// </summary>
void DoSomething();
}
public class MyObject : IMyObject
{
/// <inheritdoc/>
public void DoSomething() { }
}
internal class Program
{
static void Do()
{
typeof(MyObject).GetMember(nameof(MyObject.DoSomething)).Single().GetXmlDocsSummary();
}
static void Main(string[] args)
{
for (int i = 0; ; ++i)
{
Console.WriteLine(i);
var tasks = new[]
{
Task.Run(Do),
Task.Run(Do),
Task.Run(Do),
Task.Run(Do),
};
Task.WaitAll(tasks);
XmlDocs.ClearCache();
}
}
}
In my case, it's about running unit-tests performing a JSON validation using JsonSchema in parallel. JsonSchema is generated on the fly.
It seems that the contents of list types are not correctly checked for null whether or not non-nullable-reference-type behaviour is enabled - for example, the below code will throw a System.NullReferenceException if reference types are allowed to be null or not:
var json = "[ null ]";
var arrayOfString = JsonConvert.DeserializeObject<string[]>(json);
arrayOfString.EnsureValidNullability();
The expected behaviour for the above code is that an InvalidOperationException should be throw if the non-nullable-reference-types behaviour is enabled and nothing should happen if it's not.
I've created PR #40 to pull in some unit tests to help you diagnose.
I tried poking around with the code to see if I could create a PR with a possible solution but I'm afraid that I got lost! The first problem is that in "ValidateNullability" there is a call to obj.GetType() that doesn't check whether "obj" is null (which is why there is NullReferenceException regardless of whether the value should be allowed to be null or not) but I think that the "IEnumerable" handling has to take into account the type of items in the list and whether they're allowed to be null - I got stuck trying to do that; I could dig around and get the types of "T" that any given enumerable type might implement IEnumerable<T> for but I failed to correctly determine whether those "T" values should be Unknown, Nullable or NotNullable. I then had a quick look at the documentation here and got completely lost trying to track how to work out what generic type parameters should be marked as nullable or not!
Please let me know if I can include any additional information, example cases or other help.
When upgrading from Namotion.Reflection package 3.0.1 to 3.1.0, something broke when generating the documentation page using UseSwaggerUi3 with NSwag
This is my code for calling UseSwaggerUi3, pretty basic, and worked fine with Namotion.Reflection 3.0.1
app.UseSwaggerUi3(typeof(Startup).Assembly, settings => { settings.GeneratorSettings.Title = "MyApi"; });
However after updating to 3.1.0, the documentation page yields a 500 error:
Downgrading to 3.0.1 makes it work again.
Any settings I should change in the UseSwaggerUi3 parameters ?
I'm using .NET Framework 4.7.2 for this project.
Thanks
Whenever I try to call
Add-Type -Path "D:\Test\Namotion.Reflection.dll"
in a PowerShell session it fails with
Could not load file or assembly 'Namotion.Reflection, Version=1.0.12.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102'
.
The loading of a big .NET Core Project even with Entity Framework Core succeeds. Just the Namation.Reflection assembly cannot be loaded. Do you have any ideas what the issue could be? Any special dependencies or such? Some ideas that I could try?
Properties with summaries defined in interfaces do not have their values retrieved when calling GetXmlDocsSummary
, either on the base class or on the interface directly.
public interface IConfigInfo
{
/// <summary>
/// Test Path
/// </summary>
string Path { get; set; }
}
public class ConfigInfo : IConfigInfo
{
/// <inheritdoc />
public string Path { get; set; }
}
typeof(IConfigInfo).GetMember("Path").First().GetXmlDocsSummary(); // ""
typeof(ConfigInfo).GetMember("Path").First().GetXmlDocsSummary(); // ""
I've tried to come up with the simplest example to test how the EnsureValidNullability
extension method would work - I would expect it to throw in the following code because the "Name" property of the PersonDetails
is a string and #nullable enable
is specified for the file and the value in the JSON is null:
#nullable enable
using System;
using Namotion.Reflection;
using Newtonsoft.Json;
namespace Tester
{
static class Program
{
static void Main()
{
var json = "{ \"ID\": 123, \"Name\": null }";
var p = JsonConvert.DeserializeObject<PersonDetails>(json);
p.EnsureValidNullability();
Console.WriteLine("Shouldn't get here - line above should throw");
}
}
public sealed class PersonDetails
{
public PersonDetails(int id, string name)
{
ID = id;
Name = name;
}
public int ID { get; }
public string Name { get; }
}
}
I've recreated this using .NET Fiddle to try to make it as quick and easy to reproduce: dotnetfiddle.net/fmha4i
Hi! It's October and the Hacktoberfest is in full swing. Could you please add a hacktoberfest
label to the repo?
The ContextualMemberInfo
no longer inherits from ContextualType
.
This change appears to be happening since the 8daa916835df041d5afe5a9dae24409bd2be8034
commit.
Is there a new approach to how we should use ContextualType
?
Hi,
I'm trying to help with the following issue that generates documentation via NSwag in Azure Functions v2. I know what the problem is but I need to determine where NSwag get's the xml documentation from.
I think it's coming from this package.
In order to solve the issue, I need to be able to set a custom xml file path. In Azure Functions on the server, this is different then the path when you locally develop.
So I tracked the code through NSwag to this package and ended up with the method GetXmlDocsPath
.
So the ultimate questions are:
Generate NRT-compatible classes using Reflection.Emit
An emitted class having the same attributes as a coded one provides the same Nullability values for every property
Despite of having the very same attributes on emitted class, every emitted property is having the Unknown
nullability while the coded ones are having the Nullable
nullability.
I don't think this is a Namotion.Reflection bug, just trying to find someone to help me finding out what am I missing =)
Repro: https://github.com/bessgeor/namotion-reflection-emit-vs-roslyn (asserts the observed behavior).
Given a field declaration such as public string?[] Array;
there doesn't appear to be a way to get the nullability of the element type, as opposed to the array itself. I might have missed it, but I couldn't find anything that would let me get it anywhere.
I also need to do this for nested arrays like public string?[]?[] Array;
- so I'd actually prefer an equivalent to Type.GetElementType() that returns a ContextualType for the element type, rather than just getting the nullability of the element type, as that would allow me to traverse all element types of nested arrays, including more complex elements that have generic arguments.
C# 9 records are documented this way:
/// <summary>
/// Returns a list of items.
/// </summary>
/// <param name="PageNumber">The page number.</param>
/// <param name="PageSize">The page size.</param>
public record ListItems(int PageNumber, int PageSize);
The expectation would be that the <param>
documentation would carry over into the description
of the property when the schema is generated.
First of all, thank you for providing this library!
Could you please provide a released or tagged source of the 2.1.2 nuget package (https://www.nuget.org/packages/Namotion.Reflection/2.1.2)?
Thank you in advance!
I have some models exposed in my APIs that come from NuGetPackages.
While those types are properly documented (I can see the doc in intellisense), they have no documentation in the generated OpenApi spec.
This does not happen on netcoreapp2.1, but does happen on netcoreapp3.1.
To highlight this issue, please see this repro:
3.1 branch :
https://github.com/jeremyVignelles/TestNSwagNetCoreApp/blob/repro/doc-external-models/TestNSwagNetCoreApp/Hello.cs#L42
I used a type from the NSwag NuGet package to highlight the issue.
I noticed "Unknown" nullability was given for a nested class when the parent class contains an async method. The use case I have is I have an async unit test which use a nested test class for the unit tests of a factory method. The following is a minimal example of the problem, given the method "Test" in run in a nullable context, note that it works as expected if the async "Test" method is removed:
static void Main(string[] args)
{
// Gives Nullability: NotNullable
var data = typeof(StringData).GetProperties().First().ToContextualProperty();
// Gives Nullability: Unknown
var dataInner = typeof(Outer.StringDataInner).GetProperties().First().ToContextualProperty();
}
public class Outer
{
public async Task Test()
{
await Task.Delay(1);
}
public class StringDataInner
{
public string Text { get; } = string.Empty;
}
}
public class StringData
{
public string Text { get; } = string.Empty;
}
I'm trying to use EnsureValidNullability
in my project, but it always crashes on any record with:
System.InvalidOperationException: 'Method may only be called on a Type for which Type.IsGenericParameter is true.'
Hello,
when getting informations for the following two methods:
void Test( int test, bool bvalue );
void Test( bool bvalue = true );
When using ToContextualParameter on the parameter of the second overload, I'll get the information from the second parameter of the first overload which is wrong.
The property information for the parameter of the second method is drawn incorrectly from the dictionary because the cache key is not selective enough to distinguish between the two overloaded methods.
I am using NJsonSchema (11.0.0) with Namotion.Reflection (3.1.1) and encountered a problem during schema generation. Below is a shorted example of my usecase.
public class Hashid
{
protected long _id;
...
}
public sealed class Hashid<T> : Hashid
where T : EntityBase
{
...
}
public Request
{
public Hashid RegionId { get; set; } // works
public Hashid<Domain.Entities.User> UserId { get; set; } // fails
}
During the schema generation and exploration of the Request
the following exception is thrown:
System.InvalidOperationException: This operation is only valid on generic types.
at System.RuntimeType.GetGenericTypeDefinition()
at Namotion.Reflection.ContextualType.<get_Fields>b__36_0(FieldInfo field)
at System.Linq.Enumerable.SelectArrayIterator`2.Fill(ReadOnlySpan`1 source, Span`1 destination, Func`2 func)
at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
at Namotion.Reflection.ContextualType.get_Fields()
at NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
...
This happens because in the Fields
property of the ContextualType
class the TypeInfo
is generic but the DeclaringType
of the field is not.
This could be related to #139.
I currently resolved this issue for me by not having the Hashid<T>
inherit from Hashid
and copy part of the logic.
I'm trying to use JsonSchema.FromType<System.DirectoryServices.AccountManagement.UserPrincipal>()
but it's throwing an InvalidOperationException.
I suspect the reason is that ArrayList.GetEnumerator has an overload which is not working with
https://github.com/RicoSuter/Namotion.Reflection/blob/master/src/Namotion.Reflection/Context/ContextualType.cs#L146
I don't fully understand your code but I'd like to suggest the following possible solution
var getEnumeratorMethod = Methods.SingleOrDefault(m => m.Name == "GetEnumerator" && m.Parameters.Length == 0);
typeof(IReadOnlyList<int>).ToContextualType().EnumerableItemType
Returns Int32
in version 1.0.23.
But in the current version 2.0.10 it returns null
. (It also returns null
in 2.0.0.)
XML Docs file not reliably resolved (depending on OS/machine).
For more information see:
RicoSuter/NSwag#3465 (comment)
The big problem here is that the xml docs dlls in nuget packages (any external nuget and also asp.net core) are not put into the output folder so we need to look them up in the nuget cache folder, etc. this is super hacky at the moment. You can find the code here:
There are also unit tests for this here to test or debug this on different machines:
https://github.com/RicoSuter/Namotion.Reflection/blob/master/src/Namotion.Reflection.Tests/XmlDocsExtensionsTests.cs#L598
https://github.com/RicoSuter/Namotion.Reflection/blob/master/src/Namotion.Reflection.Tests/XmlDocsExtensionsTests.cs#L611
The problem is that this works on some machines/OSes and does not on other, so the output is not stable...
Any better idea how to solve this?
Resolution can be disabled with XmlDocs.ResolveFromNuGetCacheOrDotNetSdk = false;
In .NET core >= 3.0, when <PublishTrimmed>true</PublishTrimmed>
and the project that uses this package is published, the following libraries get trimmed, because reflection is used:
XML documentation cannot be loaded by this library. This can affect NSwag, where the generated swagger.json lacks documentation for published applications with this flag enabled. This is not blocking as the application works normally, but it's a difference between the application tested in the dev environment and the application that gets pushed into production.
You can use one of the technique described here.
For example, you could add these lines into your .csproj:
<ItemGroup>
<TrimmerRootAssembly Include="System.IO.FileSystem" />
<TrimmerRootAssembly Include="System.Xml.XPath.XDocument" />
<TrimmerRootAssembly Include="System.Xml.Linq" />
</ItemGroup>
TrimmerRootAssembly
by adding a build/<PackageName>.props
into Namotion.Reflection's package, which contains the above XML inside a <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
tag. <ItemGroup>
<None Include="build\Namotion.Reflection.props" Pack="True" PackagePath="build\" />
</ItemGroup>
Direct references to this package would then have the TrimmerRootAssembly added, and these assemblies should not get trimmed.
For indirect references (like in NJS.csproj), you can use:
<PackageReference Include="Namotion.Reflection" Version="XXX" PrivateAssets="None" />
The value of None
might be overkill here, see the doc. The idea is to tell msbuild "Let properties/item groups leak into my project, and get referenced as well when someone references me"
#if NETSTANDARD1_0
// Dynamically loaded API
#else
// API is always present, and use it directly
#endif
Netstandard & netcoreapp that get included in a netcoreapp application.
The GetXmlDocsSummary
method currently does not return a value for properties inherited from classes of other projects
A simple example:
Project A
public class MainTest
{
public static void Main() {
foreach (PropertyInfo prop in typeof(ChildClass).GetProperties())
{
Console.WriteLine("Name: " + prop.Name);
Console.WriteLine("Summary: " + prop.GetXmlDocsSummary());
}
}
}
public class ChildClass : ParentClass { }
Project B
public class ParentClass
{
/// <summary>
/// This summary will not be shown
/// </summary>
public string Value { get; set; }
}
Output:
Name: Value
Summary:
Consider the following usage of a param XML tag in the source code:
/// <param name="baz">Boolean returned from method <see cref="int.TryParse(string?, out int)"/>.</param>
When compiling the corresponding XML documentation file, it will generate:
<param name="baz">Boolean returned from method <see cref="M:System.Int32.TryParse(System.String,System.Int32@)"/>.</param>
When Namotion.Reflection.XmlDocsExtension processes this to get the XmlDocs for this parameter, the current logic results in the final value of:
Boolean returned from method Int32@).
The issue is with the logic in XmlDocsExtension.ToXmlDocsContent():
attribute = e.Attribute("cref");
if (attribute != null)
{
value.Append(attribute.Value.Trim('!', ':').Trim().Split('.').Last());
}
The current code assumes there are no '.' separators after the target type or method name in the cref.
I wish for the nuget packages to have the repository url property set correctly
By providing the repo url it will make it easier to contribute and can be used by source-link.
Had this bug while using NJsonSchema.
Repro:
public class ParentClass
{
public string Property { get; set; }
}
public class GenericChildClass<T> : ParentClass
{
}
public void Repro()
{
var ct = typeof(GenericChildClass<string>).ToContextualType()
// this fails because the property's declaring type is not generic
_ = ct.Properties;
}
Here is the code that fails in ContextualType.cs
because property.DeclaringType
(ParentClass
) isn't generic even if GenericChildClass<string>
is. The call the GetGenericTypeDefinition()
throws because ParentClass
is not generic.
if (this.TypeInfo.IsGenericType && !this.TypeInfo.ContainsGenericParameters)
{
PropertyInfo runtimeProperty = property.DeclaringType.GetGenericTypeDefinition().GetRuntimeProperty(property.Name);
I'm not sure if I'm using the library wrong but as far as I can tell I appear to be getting some incorrect results.
public class MyType
{
public (string, Uri?) MyProp { get; }
}
public static void Main(string[] args)
{
var prop = typeof(MyType).GetProperty("MyProp").ToContextualProperty();
Console.WriteLine(prop.Nullability);
Console.WriteLine(prop.GenericArguments[0].Nullability);
Console.WriteLine(prop.GenericArguments[1].Nullability);
}
I'm getting the string
as Unknown and the Uri
as NotNullable. This doesn't look like it's an issue if I change the tuple to Dictionary<,>
though so maybe it's specific to ValueTuples?
typeof(Dictionary<string, int>).ToContextualType().EnumerableItemType
returns null
.
The reason seems to be that
typeof(Dictionary<string, int>).GetRuntimeMethod("GetEnumerator", Array.Empty<Type>())
.ReturnParameter?.ToContextualParameter().Type.ToString()
returns System.Collections.Generic.Dictionary`2+Enumerator[System.String,System.Int32]
.
And the current implementation looks like:
Namotion.Reflection/src/Namotion.Reflection/Context/ContextualType.cs
Lines 160 to 165 in 4279901
Hi,
in your open api middleware you clear the XmlDocs cache with XmlDocs.ClearCache
but CachingXDocument.ElementByNameCache is not cached.
I also do not understand why this is even static. Could it not return values from the wrong document?
The GetXmlDocsSummary
method currently does not return a value for properties inherited from a generic class.
A simple example:
var type = Assembly.GetExecutingAssembly().GetTypes().First(x => x.Name.StartsWith("Child"));
foreach (var propertyInfo in type.GetProperties())
{
Console.WriteLine($"{propertyInfo.Name}: {propertyInfo.GetXmlDocsSummary()}");
}
public class GenericParent<T>
{
/// <summary>
/// This summary will be ignored.
/// </summary>
public T? Value { get; set; }
/// <summary>
/// This summary will also be ignored.
/// </summary>
public string? AnotherValue { get; set; }
}
public class Child<T>: GenericParent<T>
{
/// <summary>
/// This summary will be shown.
/// </summary>
public string? Name { get; set; }
}
Output:
Name: This summary will be shown.
Value:
AnotherValue:
For example
static void Main( string[] args )
{
var s = @"
{
""a"": {
""User"": {
""user_name"":""john.mancini"", ""Id"":123
},
""name"":""John Mancini""
},
""b"": {
""User"": {
""user_name"":""john.mancini"", ""Id"":123
},
""name"":""John Mancini""
}
}";
var obj = JsonConvert.DeserializeObject<Dictionary<string, MyClass>>( s );
obj.EnsureValidNullability();
}
public class MyClass
{
[JsonProperty( "user" )]
public User User { get; set; } = null!;
[JsonProperty( "name" )]
public string Name { get; set; } = null!;
}
public class User
{
[JsonProperty( "user_name" )]
public string UserName { get; set; } = null!;
[JsonProperty( "id" )]
public int Id { get; set; }
}
This code throws an error 'Unable to cast object of type 'System.String' to type 'test.MyClass'.'
I am not sure if it is known that there are issues related to ensuring the validations of dictionaries. If so, we can delete this issue. A similar error is thrown for Dictionary<int, T>. But T seems to have to be a custom class, or at least not int
or string
The following code works as expected, it outputs "PersonDetails.Name.Nullability: NotNullable" -
#nullable enable
using System;
using Namotion.Reflection;
namespace Tester
{
static class Program
{
static void Main()
{
Console.WriteLine("PersonDetails.Name.Nullability: " + typeof(PersonDetails).GetContextualProperties()[0].Nullability);
}
public sealed class PersonDetails
{
public PersonDetails(string name) => Name = name;
public string Name { get; }
}
}
}
(See dotnetfiddle.net/Jqdk7S)
However, if I add a second nested classed with Program
then the output becomes "PersonDetails.Name.Nullability: Unknown" -
#nullable enable
using System;
using Namotion.Reflection;
namespace Tester
{
static class Program
{
static void Main()
{
Console.WriteLine("PersonDetails.Name.Nullability: " + typeof(PersonDetails).GetContextualProperties()[0].Nullability);
}
public sealed class PersonDetails
{
public PersonDetails(string name) => Name = name;
public string Name { get; }
}
public sealed class RoleDetails
{
public RoleDetails(string name) => Name = name;
public string Name { get; }
}
}
}
(See dotnetfiddle.net/9rYIow)
Looking at the attributes that the compiler generates for these, it seems to remove the [NullableContext]
attribute from the PersonDetails
class in the second version and append it to the Program
class, though it leaves the [Nullable]
on PersonDetails
- I've started reading through your explanations of these attributes but I don't understand enough yet to be able to tell whether this could be causing the problem!
Disclaimer: I only tested in NSwag, but I assume that the root cause is in NJSonSchema. Since I don't know how things works here, I did not test in NJS. Feel free to move the issue if it doesn't belong here.
This is a continuation of RicoSuter/NSwag#1951
After implementing my property like this:
[JsonProperty(Required = Required.Always)]
[ItemsCanBeNull]
public string[] NullableStrings { get; set; } = {"Hello", null, "World"};
It is working as I expected, but now, I'm trying to migrate my code with C#8 nullables, so I tried to do that:
[JsonProperty(Required = Required.Always)]
public string?[] NullableStrings { get; set; } = {"Hello", null, "World"};
But it doesn't generate the nullability information properly, while it does on a plain string?
property.
When you have a Type
you can get a type.GetTypeInfo().TypeParameter()
.
What's the equivalent for a ContextualType
?
I'm interested in observing the nullability attributes of a type like Derived
in
public class MyBase<T> { }
public class Derived : MyBase<string?> { }
In this case NullableAttribute
for the string?
is directly placed on the Derived
type.
I tried calling ToContextualMember
and ToContextualType
on typeof(Derived)
but neither appear to expose this information - correct me if I'm wrong but it seems like this functionality isn't present in the library yet. I propose we add it and can contribute time to expedite this.
The doc for TryGetPropertyValue looks copy-patsed
Object extensions
HasProperty(): Determines whether the specified property name exists.
TryGetPropertyValue(): Determines whether the specified property name exists.
I am trying to load the documentation for NLog. The NuGet package version is 5.0.4 whereas the assembly version is 5.0.0.0.
The XmlDocsExtensions.GetXmlDocsPathFromNuGetCacheFile
uses a regex to parse the JSON encoded project.nuget.cache
file, and it builds the pattern incorrectly in this case.
Any thoughts on how to work around this?
I may have found a bug by chance while looking through the source. I think the path constructed below should be checked with DynamicApis.FileExists(path)
before returning it.
But maybe I'm misunderstanding something. In that case this issue can be closed.
Code:
using System;
using System.Reflection;
using Namotion.Reflection;
namespace ReflectionTest
{
class Program
{
public string? Test1(int i)
{
return null;
}
public Program Test1(double j)
{
return null;
}
public string? Test2(int i)
{
return null;
}
public Program Test2(double j)
{
return null;
}
static void PrintInfo(MethodInfo m)
{
var nullability = m.ReturnParameter.ToContextualParameter().Nullability;
Console.WriteLine(m.Name + "," + m.ReturnType.Name + "," + nullability);
}
static void Main(string[] args)
{
PrintInfo(typeof(Program).GetMethod("Test1", new[] { typeof(int) }));
PrintInfo(typeof(Program).GetMethod("Test1", new[] { typeof(double) }));
PrintInfo(typeof(Program).GetMethod("Test2", new[] { typeof(double) }));
PrintInfo(typeof(Program).GetMethod("Test2", new[] { typeof(int) }));
}
}
}
Expected output:
Test1,String,Nullable
Test1,Program,NotNullable
Test2,Program,NotNullable
Test2,String,Nullable
Actual output:
Test1,String,Nullable
Test1,Program,Nullable
Test2,Program,NotNullable
Test2,String,NotNullable
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.