YngveHestem.GenericParameterCollection 1.1.7-beta13

This is a prerelease version of YngveHestem.GenericParameterCollection.
There is a newer version of this package available.
See the version list below for details.
dotnet add package YngveHestem.GenericParameterCollection --version 1.1.7-beta13                
NuGet\Install-Package YngveHestem.GenericParameterCollection -Version 1.1.7-beta13                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="YngveHestem.GenericParameterCollection" Version="1.1.7-beta13" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add YngveHestem.GenericParameterCollection --version 1.1.7-beta13                
#r "nuget: YngveHestem.GenericParameterCollection, 1.1.7-beta13"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install YngveHestem.GenericParameterCollection as a Cake Addin
#addin nuget:?package=YngveHestem.GenericParameterCollection&version=1.1.7-beta13&prerelease

// Install YngveHestem.GenericParameterCollection as a Cake Tool
#tool nuget:?package=YngveHestem.GenericParameterCollection&version=1.1.7-beta13&prerelease                

GenericParameterCollection

ParameterCollection is a simple to use collection for different parameters and types defined with a key. It supports many of the standard types like int, string, double, float, long, DateTime, bool, byte[], enums and more. It can also support nearly every other objects by easy converting the object to it´s own ParameterCollection, which can be nested togheter as parameters. It also supports many of the parameters as IEnumerables (List, Array, etc.). Methods to convert to and from JSON is also included.

How to use this package

The easiest way to use the package is to download it from nuget: https://www.nuget.org/packages/YngveHestem.GenericParameterCollection/

Supported types

Currently, these C#-types are supported out of the box, with some conversion between themselves.

  • int
  • string
  • double
  • long
  • float
  • decimal
  • byte[]
  • bool
  • DateTime
  • ParameterCollection
  • IEnumerable of int
  • IEnumerable of string
  • IEnumerable of double
  • IEnumerable of long
  • IEnumerable of float
  • IEnumerable of decimal
  • IEnumerable of bool
  • IEnumerable of DateTime
  • IEnumerable of ParameterCollection
  • Enum-types
  • IEnumerable of objects of types that use attribute-converters
  • Nullable types of the one above (int?, double?, IEnumerable of int?, etc.)

Converters for other types are easy to implement.

It also supports selecting an entry between different choices. It also support to select multiple choices.

For the possibillity to differentiate if it should be possible to write multiline or not in a string, and if both the date and time is important in a DateTime, this is also possible to differentiate. This can for example be useful if you for example autogenerates input-forms for a gui.

It is also possible to add multiple parameters to a parameter, which can be used to send much more information togheter with a parameter, or be used to validate the input the way a backend wants it in GUI-level.

When should I use this?

The ParameterCollection was not written to be used instead of classes. This was primarly written to be used with Interfaces or other similar situations where the classes who implements an interface can get nearly any number and different type of response from a user. It is also suitable in other situations where much input from a user is required. This as it is relatively easy to create a GUI with reusable controls for the user that can be used over and over again, instead of manually define the controls for each parameter/input by hand.

Concrete example

A concrete example will be a program that let you create an image. This program uses an interface to define everything you can do with the image. Like creating different shapes or blurring image.

Different shapes need different forms of parameters. A rectangle will need a starting point and some hight and width sizes. A circle will need a position and a radius. They might also need for example colors or brushes (or not). Then something like this is needed.

Custom converters

While the package has some default converters built in, you can add nearly any value as a parameter by creating custom converters. It is mainly two ways to create custom converters.

Create converters with the use of attributes

Maybe the simplest possible way of creating converters on your own classes will be to use some custom attributes on a type you want to convert. See the examples below for how you can implement different converters.

When using attributes, simple ienumerables of theese objects are also supported by default.

Attributes you can use when creating a custom converter based on attributes

Remember to look at the examples for how this is done.

AttributeConvertibleAttribute

To mark a class or struct as convertable via attributes, this has to be set on the given class/struct. If not set, it will not convert the class as this even if it has other attributes.

This has a property where you can set which ParameterType it should preferably convert to. As of this writing, only the default ParameterCollection is supported.

This has also some parameters regarding how the class wants to give a default value if some code asks for it (many of the editors may for instance need it if handling an IEnumerable of the class). The parameters are "DefaultValueHandling", "DefaultValueKey" and "DefaultValueArguments".

DefaultValueHandling lets you decide if you want it to be any default value at all. Of course, the code that calls it might not respect it, but hopefully it does. The default value is InitializeNewObject, which means it will create a new object. But if that is not wanted, this propertycan be set to None.

DefaultValueKey gives the wanted key that should be used if added to the additionalInfo of for instance the IEnumerable. The default value is "defaultValue", which is the key used on many of the knnown editors.

DefaultValueArguments gives you a chance to set the arguments used on the constructor when creating that new object.

The IEnumerable-converter for the AttributeConvertibles will use theese properties when deciding what to do with parameters that don't have the defaultValue set in additionalInfo.

ParameterPropertyAttribute

This attribute should be marked on any field or property in the class/struct that should be converted. Only the marked properties/fields are converted.

This has a property "Key" and a property "ParameterType", and some constructors.

None of the properties needs to be set though. If ParameterType is omitted, the converter will do it's best to find the correct ParameterType based on either the given value's type, or if value is null, the type is based on the property's Type. This means that if the property's type is an interface, and the value is Null, the interface-type is used to convert this property. But if it has a value, that implementation of the interface is used to find the best ParameterType.

If the Key-property is omitted, the converter will use the name of the property/field as the key.

AdditionalInfoAttribute

This attribute can be used on both classes, structs, enums, properties and fields. This will as the name implies, add an AdditionalInfo-property to the given class/struct/enum/property/field. This can become handy if you want to tell something more than the value and name to the parts that use it (like and editor). For example if you have a property that can be in only a given range, this could be used.

The attribute has the properties "Key", "Value", "OvverrideIfKeyExist", "ParameterType", "KeyIsPath", "KeyPathDivider" and "ParameterTypeIsSet".

The Key- and Value-properties are of course mandatory.

The property OverrideIfKeyExist has a default value of false. This property just says that if the additioalInfo already has a property with that name, should it override the value (if this property is true), or not.

ParameterType just declares the ParameterType. If not set, the converter will do it's best to find the correct value. Since attributes has a very limited number of value-types, this means that if you for instance want to set a Date- or DateTime-value, you would need to define the value as string, and set the ParameterType directly, as the parameter else most likely would be set as string. The ParameterTypeIsSet is a get-parameter that is true if you set the ParameterType.

The property KeyIsPath is by default false. If set to true, this will tell the converter that the key is not just defining the key for it's own property, that should be set in the additionalInfo, but is defining that the property should be in another property in the additionalInfo. The path can consist of many stages out from the additionalInfo, but will of course all need to be a ParameterCollection, except the property, which can be anything.

The property KeyPathDivider is by default ".", and defines what the divider between the Path-parts should be.

For different ways to use AdditionalInfo, look at the correct examples below, and in the TestProject.

Create a converter-class to convert between values

It is possible to convert a object to and from any ParameterType by creating a class that implement the IParameterValueConverter.

If you will make converter class between the ParameterType ParameterCollection and a single object type (per converter-class), you can instead of implementing IParameterValueConverter directly, create a class that inherit from the class ParameterCollectionParameterConverter<TValueType>. This class do some of the heavy lifting for you. TValueType will here be the type that should be converted to/from a ParameterCollection.

A quick note about how null-value is handled

As we handle null-values, this will mean that both the rawValue and value in the converters can be null.

Another thing to mark is that the default converters will make an exception if you try to get a value that is null as a type that can not contain null (for instance you can not convert a null value to int, but you can convert it to int?). If you want to return for instance a default value if the value is null and you try to get it as a type that are not able to be null, you will be able to do that by creating a custom converter.

GUI-frontends

Here is a list of known packages that will provide an editor for a given framework (mark that some may be more finished, updated and in better shape than others):

Have you made a package that will fit here? Create an issue with link or create a PR.

Code-Examples

Simple use

In the code-block below, you can see some of the different methods in use.

var parameters = new ParameterCollection();
parameters.Add("1+1", 2);											// int
parameters.Add("5+5", 10);											// int
parameters.Add("Day", true);										// bool
parameters.Add("name", "William Wallace", false);					// string
parameters.Add("description", "- He was a knight." +
	Environment.NewLine + "- He was scottish", true);				// string (defined as multiline)

var answer = parameters.GetByKey<int>("1+1");						// returns 2 as an int
var name = parameters.GetByKey("name");								// returns the name as a string
var parameterTypeDay = parameters.GetParameterType("Day");			// returns ParameterType.Bool
var descriptionType = parameters.GetParameterType("description");   // returns ParameterType.String_Multiline
var nameType = parameters.GetParameterType("name");                 // returns ParameterType.String

var hasKeyNight = parameters.HasKey("Night");                       // returns false

var json = parameters.ToJson();                                     // Convert the collection to a json-string.

var parameters2 = ParameterCollection.FromJson(json);				// Get a new ParameterCollection-object from a json-string.

Add a custom type as a parameter without using custom converters

Below you can see a example for how to define some structures and convert it. The example also show the use of a custom enum, that are supported without any converting.

    public class ExampleConversionWithoutConverters
    {
        public ParameterCollection DefineAnExampleSchool()
        {
            var school = new ParameterCollection();
            school.Add("name", "Au High School");
            school.Add("headmaster", new Person
            {
                Name = "Rick Rickerson",
                Gender = Sex.Male,
                BirthDate = new DateTime(1960, 1, 23),
                Summary = "He has done a lot of work"
            }.ToParameterCollection());
            return school;
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public Sex Gender { get; set; }
        public DateTime BirthDate { get; set; }
        public string Summary { get; set; }

        public ParameterCollection ToParameterCollection()
        {
            return new ParameterCollection
            {
                { "name", Name, false },
                { "gender", Gender },
                { "birthDate", BirthDate, true },
                { "summary", Summary, true }
            };
        }

        public static Person FromParameterCollection(ParameterCollection person)
        {
            return new Person
            {
                Name = person.GetByKey<string>("name"),
                Gender = person.GetByKey<Sex>("gender"),
                BirthDate = person.GetByKey<DateTime>("birthDate"),
                Summary = person.GetByKey<string>("summary")
            };
        }
    }

    public enum Sex
    {
        Male,
        Female,
        Other
    }

Add a custom type as a parameter by using a custom converter

Below you can see a example for how to define some structures and convert it using a custom converter for the Person-class. The example also show the use of a custom enum, that are supported without any converting.

Since the Person-class converts to ParameterCollection, the converter-class derives from ParameterCollectionParameterConverter<T>.

    public class ExampleConversionWithConverter
    {
        private static IParameterValueConverter[] _parameterValueConverters = new IParameterValueConverter[]
        {
            new PersonConverter()
        };

        public ParameterCollection DefineAnExampleSchool()
        {
            var school = new ParameterCollection();
            school.Add("name", "Au High School");
            school.Add("headmaster", new Person
            {
                Name = "Rick Rickerson",
                Gender = Sex.Male,
                BirthDate = new DateTime(1960, 1, 23),
                Summary = "He has done a lot of work"
            }, null, _parameterValueConverters);
            return school;
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public Sex Gender { get; set; }
        public DateTime BirthDate { get; set; }
        public string Summary { get; set; }
    }

    public enum Sex
    {
        Male,
        Female,
        Other
    }

    public class PersonConverter : ParameterCollectionParameterConverter<Person>
    {
        protected override bool CanConvertFromParameterCollection(ParameterCollection value, IEnumerable<IParameterValueConverter> customConverters)
        {
            return value.HasKeyAndCanConvertTo("name", typeof(string))
                && value.HasKeyAndCanConvertTo("gender", typeof(Sex))
                && value.HasKeyAndCanConvertTo("birthDate", typeof(DateTime))
                && value.HasKeyAndCanConvertTo("summary", typeof(string));
        }

        protected override bool CanConvertToParameterCollection(Person value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return true;        // As the object type is already checked, and I currently have no other reason to check anything in the object to know if I can convert it or not, I just return true.
        }

        protected override Person ConvertFromParameterCollection(ParameterCollection value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new Person
            {
                Name = value.GetByKey<string>("name"),
                Gender = value.GetByKey<Sex>("gender"),
                BirthDate = value.GetByKey<DateTime>("birthDate"),
                Summary = value.GetByKey<string>("summary")
            };
        }

        protected override ParameterCollection ConvertToParameterCollection(Person value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new ParameterCollection
            {
                { "name", value.Name },
                { "gender", value.Gender },
                { "birthDate", value.BirthDate },
                { "summary", value.Summary }
            };
        }
    }

Add a custom type as a parameter by using a custom converter for both the parameter and the whole ParameterCollection

Below you can see a example for how to define some structures and convert it using both a custom converter for the Person-class and defining a class for the School and convert it to a ParameterCollection directly via a custom converter. The example also show the use of a custom enum, that are supported without any converting.

Since both the Person and School-classes converts to ParameterCollection, both the converter-classes derives from ParameterCollectionParameterConverter<T>.

    public class ExampleConversionWithConverterWithSchool
    {
        private static IParameterValueConverter[] _parameterValueConverters = new IParameterValueConverter[]
        {
            new SchoolConverter()
        };

        public ParameterCollection DefineAnExampleSchool()
        {
            var schoolObject = new School
            {
                Name = "Au High School",
                Headmaster = new Person
                {
                    Name = "Rick Rickerson",
                    Gender = Sex.Male,
                    BirthDate = new DateTime(1960, 1, 23),
                    Summary = "He has done a lot of work"
                }
            };
            return ParameterCollection.FromObject(schoolObject, _parameterValueConverters);
        }

        public School GetSchool(ParameterCollection parameters)
        {
            return parameters.ToObject<School>(_parameterValueConverters);
        }
    }

    public class School
    {
        public string Name { get; set; }
        public Person Headmaster { get; set; }
    }

    public class Person
    {
        public string Name { get; set; }
        public Sex Gender { get; set; }
        public DateTime BirthDate { get; set; }
        public string Summary { get; set; }
    }

    public enum Sex
    {
        Male,
        Female,
        Other
    }

    public class PersonConverter : ParameterCollectionParameterConverter<Person>
    {
        protected override bool CanConvertFromParameterCollection(ParameterCollection value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return value.HasKeyAndCanConvertTo("name", typeof(string))
                && value.HasKeyAndCanConvertTo("gender", typeof(Sex))
                && value.HasKeyAndCanConvertTo("birthDate", typeof(DateTime))
                && value.HasKeyAndCanConvertTo("summary", typeof(string));
        }

        protected override bool CanConvertToParameterCollection(Person value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return true;        // As the object type is already checked, and I currently have no other reason to check anything in the object to know if I can convert it or not, I just return true.
        }

        protected override Person ConvertFromParameterCollection(ParameterCollection value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new Person
            {
                Name = value.GetByKey<string>("name"),
                Gender = value.GetByKey<Sex>("gender"),
                BirthDate = value.GetByKey<DateTime>("birthDate"),
                Summary = value.GetByKey<string>("summary")
            };
        }

        protected override ParameterCollection ConvertToParameterCollection(Person value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new ParameterCollection
            {
                { "name", value.Name },
                { "gender", value.Gender },
                { "birthDate", value.BirthDate },
                { "summary", value.Summary }
            };
        }
    }

    public class SchoolConverter : ParameterCollectionParameterConverter<School>
    {
        private static IParameterValueConverter[] _parameterValueConverters = new IParameterValueConverter[]
        {
            new PersonConverter()
        };

        protected override bool CanConvertFromParameterCollection(ParameterCollection value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return value.HasKeyAndCanConvertTo("name", typeof(string)) && value.HasKeyAndCanConvertTo("headmaster", typeof(Person), _parameterValueConverters);
        }

        protected override bool CanConvertToParameterCollection(School value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return true;         // As the object type is already checked, and I currently have no other reason to check anything in the object to know if I can convert it or not, I just return true.
        }

        protected override School ConvertFromParameterCollection(ParameterCollection value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new School
            {
                Name = value.GetByKey<string>("name"),
                Headmaster = value.GetByKey<Person>("headmaster", _parameterValueConverters)
            };
        }

        protected override ParameterCollection ConvertToParameterCollection(School value, ParameterCollection additionalInfo, IEnumerable<IParameterValueConverter> customConverters)
        {
            return new ParameterCollection
            {
                { "name", value.Name },
                { "headmaster", value.Headmaster, null, _parameterValueConverters }
            };
        }
    }

Mark that the example above sets the custom converter of the person inside the school-converter, which ensures that the school-converter are not dependent on that other converters is also given. But it is also possible to let the school-converter expect that the person-converter are given as a custom converter by using the customConverter-parameters in the converter.

Add types by using attributes instead of custom converters

Here comes an example for using some custom attributes to convert an object to and from ParameterCollection. This might make it easier to convert objects you have at your disposal, as you can mark the object with some attributes.

Example code
public class ExampleWithAttributeConversion
    {
        public ParameterCollection DefineExamplePerson()
        {
            var color = new ExampleColor
            {
                Blue = 0.5f,
                Red = 0.9f
            };

            return ParameterCollection.FromObject(new Person("Rick Mortimer", color));
        }

        public Person GetPersonObject(ParameterCollection parameters)
        {
            return parameters.ToObject<Person>();
        }
    }

    [AttributeConvertible]
    [AdditionalInfo("type", "color")]
	public class ExampleColor
	{
        [ParameterProperty("r")]
		[AdditionalInfo("desc", "How much red color. Goes from 0 to 1.")]
        [AdditionalInfo("minValue", 0.0f)]
        [AdditionalInfo("maxValue", 1.0f)]
		public float Red { get; set; } = 1;

        [ParameterProperty("g")]
        [AdditionalInfo("desc", "How much green color. Goes from 0 to 1.")]
        [AdditionalInfo("minValue", 0.0f)]
        [AdditionalInfo("maxValue", 1.0f)]
        public float Green { get; set; } = 1;

        [ParameterProperty("b")]
        [AdditionalInfo("desc", "How much blue color. Goes from 0 to 1.")]
        [AdditionalInfo("minValue", 0.0f)]
        [AdditionalInfo("maxValue", 1.0f)]
        public float Blue { get; set; } = 1;

        [ParameterProperty("a")]
        [AdditionalInfo("desc", "Should the color be transparent or not (or something in between). Goes from 0 to 1.")]
        [AdditionalInfo("minValue", 0.0f)]
        [AdditionalInfo("maxValue", 1.0f)]
        public float Alpha { get; set; } = 1;
	}

    [AttributeConvertible]
    public class Person
    {
        [ParameterProperty("name")]
        private string _name;

        [ParameterProperty]
        private ExampleColor _favoriteColor;

        public Person()
        {
            _name = "Unknown";
            _favoriteColor = new ExampleColor();
        }

        public Person(string name, ExampleColor color)
        {
            _name = name;
            _favoriteColor = color;
        }
    }
How do the attributes work

In the example code, we have two classes that will be converted based on the attribute-notations. The ExampleColor-class and the Person-class.

Both classes have the [AttributeConvertible] attribute set. This tells the converter to convert this class using the given attributes.

We can see that all the properties and fields we want to convert has the attribute [ParameterProperty] set. This can either be used without given any parameters (as we can see with Persons-class property _favoriteColor), then the given property name will be used as a key, or with a specified key (as the other properties are). You are also able to specify a ParameterType if you want. If this is not set, the system will try to find the best suitable ParameterType for you.

In the example code above we do also use another custom attribute. This is the [AdditionalInfo] attribute. This attribute can be used to populate the AdditionalInfo-ParameterCollection for given property. As you might see, even the class itself can have this parameter, and this will be set to the parent-parameter's additionalInfo if a parent parameter exists.

While the [AttributeConvertible] attribute needs to be set for the [AdditionalInfo] attributes on the classes properties to be used. Any [AdditionalInfo] attributes on the class itself will be picked up even if no [AttributeConvertible] is used.

Mark that all classes that will be converted using attributes currently needs to have a parameterless constructor.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on YngveHestem.GenericParameterCollection:

Package Downloads
YngveHestem.GenericParameterCollection.RadzenBlazor

This provides controls for using GenericParameterCollection in a Blazor-application by using Radzen.Blazor-components.

YngveHestem.GenericParameterCollection.EtoForms

This provides controls for using GenericParameterCollection in the GUI-framework Eto.Forms.

YngveHestem.GenericParameterCollection.Maui

This provides controls for using GenericParameterCollection in .NET MAUI.

YngveHestem.GenericParameterCollection.Console

This provides controls for using GenericParameterCollection in a Console-application.

YngveHestem.GenericParameterCollection.Avalonia

This provides controls for using GenericParameterCollection in an AvaloniaUI-application.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.7 198 10/18/2024
1.1.7-beta13 55 10/17/2024
1.1.7-beta12 57 10/16/2024
1.1.7-beta11 71 10/5/2024
1.1.7-beta10 70 10/5/2024
1.1.7-beta09 68 10/2/2024
1.1.7-beta08 67 10/2/2024
1.1.7-beta07 69 10/1/2024
1.1.7-beta06 64 10/1/2024
1.1.7-beta05 64 10/1/2024
1.1.7-beta04 68 9/30/2024
1.1.7-beta03 69 9/30/2024
1.1.7-beta02 79 9/30/2024
1.1.7-beta01 66 9/30/2024
1.1.6 91 9/17/2024
1.1.5 120 7/11/2024
1.1.5-beta02 62 7/11/2024
1.1.5-beta01 71 7/11/2024
1.1.4 136 7/7/2024
1.1.3 99 6/25/2024
1.1.2 100 6/14/2024
1.1.1 178 4/23/2024
1.1.0 252 2/18/2024
1.0.2 195 2/4/2024
1.0.2-beta24 95 1/27/2024
1.0.2-beta23 205 10/28/2023
1.0.2-beta22 175 7/8/2023
1.0.2-beta21 137 7/8/2023
1.0.2-beta20 137 7/8/2023
1.0.2-beta19 184 6/4/2023
1.0.2-beta18 132 6/4/2023
1.0.2-beta17 124 6/4/2023
1.0.2-beta16 172 4/8/2023
1.0.2-beta15 280 4/3/2023
1.0.2-beta14 114 4/2/2023
1.0.2-beta13 129 4/2/2023
1.0.2-beta12 126 4/2/2023
1.0.2-beta11 139 4/2/2023
1.0.2-beta10 132 4/1/2023
1.0.2-beta09 138 4/1/2023
1.0.2-beta08 135 4/1/2023
1.0.2-beta07 138 4/1/2023
1.0.2-beta06 141 4/1/2023
1.0.2-beta05 136 3/22/2023
1.0.2-beta04 134 3/22/2023
1.0.2-beta03 144 3/3/2023
1.0.2-beta02 151 3/2/2023
1.0.2-beta01 159 2/5/2023
1.0.1 299 2/1/2023
1.0.0 286 1/25/2023

Breaking change:
       - Added additionalInfo as an input to the IParameterValueConverter-methods.

       Other changes:
       - Added an optional parameter to the ToJson()-method in ParameterCollection, so you can get an indented/readable version of the JSON if wanted.
       - Added an optional parameter to the AdditionalInfoAttribute, which will make it possible to ddefine the ParameterType. As Attributes only support a limited set of c#-types, something that should maybe be of a type like Date, the code would think is normal string without this specification. Mark that the code stll will get the suggested ParameterType if not specified.
       - Added other parameters to the AdditionalInfoAttribute to help deciding how DefaultValues are handled.
       - Added a couple of virtual methods on ParameterCollectionParameterConverter to let the default virtual handling of the IEnumerables set a default value in additionalInfo if not already set.
       - Added the possibillity to set a path in the AdditionalInfoAttribute-Key. This means that if you want to set a parameter in another ParameterCollection inside the AdditionalInfo, this is now possible.
       - Changed the json-serializer to have setting FloatParseHandling as FloatParseHandling.Decimal not the default FloatParseHandling.Double. This so the values are saved accuratly.
       - Fixed a small bug that made it so AttributeConvertibles fields that was null, made a big error on conversion.
       - Fixed also some other bugs that were found around null-conversion that was not caught before.
       - On AttributeConvertibles, fixed so a property or field that has a value, uses that value to determine the type, and only use the property's direct type if the value is null. This will make it so a property with for example interface, will give the concrete type that implements it, as long as it is not null.
       - Fixed a small bug that did so big/small numbers in some number-types gave an error when converting from parameter.