示例#1
0
        public void StringAndByteArray()
        {
            var cm = new ConverterManager(); // empty

            // No default byte[]-->Wrapper conversion.
            var fromBytes = cm.GetConverter <byte[], Wrapper, Attribute>();

            Assert.Null(fromBytes);

            // Add a string-->Wrapper conversion
            cm.AddConverter <string, Wrapper>(str => new Wrapper {
                Value = str
            });

            var     fromString = cm.GetConverter <string, Wrapper, Attribute>();
            Wrapper obj1       = fromString("abc", null);

            Assert.Equal("abc", obj1.Value);

            // Now we can get a byte-->string  , composed from a default (byte[]-->string) + supplied (string-->Wrapper)
            byte[] bytes = Encoding.UTF8.GetBytes("abc");

            fromBytes = cm.GetConverter <byte[], Wrapper, Attribute>();
            Assert.NotNull(fromBytes);
            Wrapper obj2 = fromBytes(bytes, null);

            Assert.Equal("abc", obj2.Value);

            // Now override the default. Uppercase the string so we know it used our custom converter.
            cm.AddConverter <byte[], string>(b => Encoding.UTF8.GetString(b).ToUpper());
            fromBytes = cm.GetConverter <byte[], Wrapper, Attribute>();
            Wrapper obj3 = fromBytes(bytes, null);

            Assert.Equal("ABC", obj3.Value);
        }
示例#2
0
        public void AttributeOverloads2()
        {
            var cm = new ConverterManager(); // empty

            cm.AddConverter <Wrapper, string, TestAttribute>((x, attr) => string.Format("[t1:{0}-{1}]", x.Value, attr.Flag));
            cm.AddConverter <Wrapper, string>(x => string.Format("[common:{0}]", x.Value));

            // This has an exact match on attribute and gives the specific function we registered.
            var func1 = cm.GetConverter <Wrapper, string, TestAttribute>();

            Assert.NotNull(func1);
            var x1 = func1(new Wrapper {
                Value = "x"
            }, new TestAttribute("y"));

            Assert.Equal("[t1:x-y]", x1);

            // Nothing registered for this attribute, so we return the converter that didn't require any attribute.
            var func2 = cm.GetConverter <Wrapper, string, TestAttribute2>();

            Assert.NotNull(func2);
            var x2 = func2(new Wrapper {
                Value = "x"
            }, new TestAttribute2("y"));

            Assert.Equal("[common:x]", x2);
        }
示例#3
0
        public void UseValueBindingContext()
        {
            var cm = new ConverterManager(); // empty

            Guid instance    = Guid.NewGuid();
            var  testContext = new ValueBindingContext(new FunctionBindingContext(instance, CancellationToken.None, null), CancellationToken.None);

            cm.AddConverter((object obj, Attribute attr, ValueBindingContext ctx) => {
                Assert.Same(ctx, testContext);
                var result  = JObject.FromObject(obj);
                result["$"] = ctx.FunctionInstanceId;
                return(result);
            });
            cm.AddConverter <string, Wrapper>(str => new Wrapper {
                Value = str
            });

            // Expected:
            //    Other --> JObject,
            //    JObject --> string ,  (builtin)
            //    string --> Wrapper
            var func = cm.GetConverter <Other, Wrapper, Attribute>();

            var value = new Other {
                Value2 = "abc"
            };
            Wrapper x1 = func(value, null, testContext);

            Assert.Equal(@"{
  ""Value2"": ""abc"",
  ""$"": """ + instance.ToString() + @"""
}", x1.Value);
        }
        public void OpenTypeConverterWithOneGenericArg()
        {
            var cm = new ConverterManager();

            // Register a converter builder.
            // Builder runs once; converter runs each time.
            // Uses open type to match.
            // Also test the IEnumerable<OpenType> pattern.

            cm.AddConverter <OpenType, IEnumerable <OpenType>, Attribute>(typeof(TypeConverterWithOneGenericArg <>));

            var attr = new TestAttribute(null);
            {
                // Doesn't match since the OpenTypes would resolve to different Ts
                var converter = cm.GetSyncConverter <object, IEnumerable <int>, Attribute>();
                Assert.Null(converter);
            }
            {
                var converter = cm.GetSyncConverter <int, IEnumerable <int>, Attribute>();
                Assert.Equal(new int[] { 1, 1, 1 }, converter(1, attr, null));
            }

            {
                var converter = cm.GetSyncConverter <string, IEnumerable <string>, Attribute>();
                Assert.Equal(new string[] { "a", "a", "a" }, converter("a", attr, null));
            }
        }
示例#5
0
        public void UseValueBindingContext()
        {
            var cm = new ConverterManager(); // empty

            Guid instance    = Guid.NewGuid();
            var  testContext = new ValueBindingContext(new FunctionBindingContext(instance, CancellationToken.None, null), CancellationToken.None);

            cm.AddConverter((object obj, Attribute attr, ValueBindingContext ctx) => {
                Assert.Same(ctx, testContext);
                var result  = JObject.FromObject(obj);
                result["$"] = ctx.FunctionInstanceId;
                return(result);
            });
            cm.AddConverter <string, Wrapper>(str => new Wrapper {
                Value = str
            });

            // Expected:
            //    Other --> JObject,
            //    JObject --> string ,  (builtin)
            //    string --> Wrapper
            var func = cm.GetConverter <Other, Wrapper, Attribute>();

            var value = new Other {
                Value2 = "abc"
            };
            Wrapper x1 = func(value, null, testContext);
            // strip whitespace
            string val      = Regex.Replace(x1.Value, @"\s", "");
            string expected = String.Format("{{\"Value2\":\"abc\",\"$\":\"{0}\"}}", instance);

            Assert.Equal(expected, val);
        }
示例#6
0
        /// <summary>
        /// Register a new converter function that is influenced by the attribute.
        /// If TSource is object, then this converter is applied to any attempt to convert to TDestination.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <typeparam name="TDestination">Destination type.</typeparam>
        /// <typeparam name="TAttribute">Attribute on the binding. </typeparam>
        /// <param name="converterManager"></param>
        /// <param name="converter">A function to convert from the source to the destination type.</param>
        public static void AddConverter <TSource, TDestination, TAttribute>(this ConverterManager converterManager, FuncAsyncConverter converter)
            where TAttribute : Attribute
        {
            FuncConverterBuilder builder = (srcType, destType) => converter;

            converterManager.AddConverter <TSource, TDestination, TAttribute>(builder);
        }
        public void OpenTypeTest()
        {
            int count = 0;
            var cm    = new ConverterManager();

            // Register a converter builder.
            // Builder runs once; converter runs each time.
            // Uses open type to match.
            cm.AddConverter <TypeWrapperIsString, int, Attribute>(
                (typeSrc, typeDest) =>
            {
                count++;
                Assert.Equal(typeof(String), typeSrc);
                Assert.Equal(typeof(int), typeDest);

                FuncAsyncConverter converter2 = (input, attr, ctx) =>
                {
                    string s = (string)input;
                    return(Task.FromResult <object>(int.Parse(s)));
                };
                return(converter2);
            });

            var converter = cm.GetSyncConverter <string, int, Attribute>();

            Assert.NotNull(converter);
            Assert.Equal(12, converter("12", new TestAttribute(null), null));
            Assert.Equal(34, converter("34", new TestAttribute(null), null));

            Assert.Equal(1, count); // converterBuilder is only called once.

            // 'char' as src parameter doesn't match the type predicate.
            Assert.Null(cm.GetSyncConverter <char, int, Attribute>());
        }
        public void StringAndByteArray()
        {
            var cm = new ConverterManager(); // empty             

            // No default byte[]-->Wrapper conversion. 
            var fromBytes = cm.GetConverter<byte[], Wrapper, Attribute>();
            Assert.Null(fromBytes);

            // Add a string-->Wrapper conversion
            cm.AddConverter<string, Wrapper>(str => new Wrapper { Value = str });

            var fromString = cm.GetConverter<string, Wrapper, Attribute>();
            Wrapper obj1 = fromString("abc", null);
            Assert.Equal("abc", obj1.Value);

            // Now we can get a byte-->string  , composed from a default (byte[]-->string) + supplied (string-->Wrapper)
            byte[] bytes = Encoding.UTF8.GetBytes("abc");

            fromBytes = cm.GetConverter<byte[], Wrapper, Attribute>();
            Assert.NotNull(fromBytes);
            Wrapper obj2 = fromBytes(bytes, null);
            Assert.Equal("abc", obj2.Value);

            // Now override the default. Uppercase the string so we know it used our custom converter.
            cm.AddConverter<byte[], string>(b => Encoding.UTF8.GetString(b).ToUpper());
            fromBytes = cm.GetConverter<byte[], Wrapper, Attribute>();
            Wrapper obj3 = fromBytes(bytes, null);
            Assert.Equal("ABC", obj3.Value);
        }
示例#9
0
        public void AttributeOverloads()
        {
            var cm = new ConverterManager(); // empty

            cm.AddConverter <Wrapper, string, TestAttribute>((x, attr) => string.Format("[t1:{0}-{1}]", x.Value, attr.Flag));
            cm.AddConverter <Wrapper, string, TestAttribute2>((x, attr) => string.Format("[t2:{0}-{1}]", x.Value, attr.Flag));

            // Since converter was registered for a specific attribute, it must be queried by that attribute.
            var funcMiss = cm.GetConverter <Wrapper, string, Attribute>();

            Assert.Null(funcMiss);

            // Each attribute type has its own conversion function
            var func1 = cm.GetConverter <Wrapper, string, TestAttribute>();

            Assert.NotNull(func1);
            var x1 = func1(new Wrapper {
                Value = "x"
            }, new TestAttribute("y"));

            Assert.Equal("[t1:x-y]", x1);

            var func2 = cm.GetConverter <Wrapper, string, TestAttribute2>();

            Assert.NotNull(func2);
            var x2 = func2(new Wrapper {
                Value = "x"
            }, new TestAttribute2("y"));

            Assert.Equal("[t2:x-y]", x2);
        }
示例#10
0
        /// <summary>
        /// Register a new converter function that is influenced by the attribute.
        /// If TSource is object, then this converter is applied to any attempt to convert to TDestination.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <typeparam name="TDestination">Destination type.</typeparam>
        /// <typeparam name="TAttribute">Attribute on the binding. </typeparam>
        /// <param name="converterManager"></param>
        /// <param name="converter">A function to convert from the source to the destination type.</param>
        public static void AddConverter <TSource, TDestination, TAttribute>(this ConverterManager converterManager, FuncAsyncConverter <TSource, TDestination> converter)
            where TAttribute : Attribute
        {
            FuncAsyncConverter   func    = (src, attr, context) => Task.FromResult <object>(converter((TSource)src, attr, context));
            FuncConverterBuilder builder = (srcType, destType) => func;

            converterManager.AddConverter <TSource, TDestination, TAttribute>(builder);
        }
示例#11
0
        /// <summary>
        /// Add a converter for the given Source to Destination conversion.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <typeparam name="TDestination">Destination type.</typeparam>
        /// <typeparam name="TAttribute">Attribute on the binding. </typeparam>
        /// <param name="converterManager">Instance of Converter Manager.</param>
        /// <param name="converterInstance">Instance of an object with convert methods on it.</param>
        public static void AddConverter <TSource, TDestination, TAttribute>(
            this ConverterManager converterManager,
            object converterInstance)
            where TAttribute : Attribute
        {
            var patternMatcher = PatternMatcher.NewObj(converterInstance);

            converterManager.AddConverterBuilder <TSource, TDestination, TAttribute>(patternMatcher);
        }
        public void Inheritence()
        {
            var cm = new ConverterManager(); // empty             
            var func = cm.GetConverter<DerivedWrapper, Wrapper, Attribute>();

            var obj = new DerivedWrapper { Value = "x" };
            Wrapper x1 = func(obj, null);
            Assert.Same(x1, obj);
        }
示例#13
0
        /// <summary>
        /// Add a converter for the given Source to Destination conversion.
        /// The typeConverter type is instantiated with the type arguments and constructorArgs is passed.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <typeparam name="TDestination">Destination type.</typeparam>
        /// <typeparam name="TAttribute">Attribute on the binding. </typeparam>
        /// <param name="converterManager">Instance of Converter Manager.</param>
        /// <param name="typeConverter">A type with conversion methods. This can be generic and will get instantiated with the
        /// appropriate type parameters. </param>
        /// <param name="constructorArgs">Constructor Arguments to pass to the constructor when instantiated. This can pass configuration and state.</param>
        public static void AddConverter <TSource, TDestination, TAttribute>(
            this ConverterManager converterManager,
            Type typeConverter,
            params object[] constructorArgs)
            where TAttribute : Attribute
        {
            var patternMatcher = PatternMatcher.New(typeConverter, constructorArgs);

            converterManager.AddConverterBuilder <TSource, TDestination, TAttribute>(patternMatcher);
        }
示例#14
0
        public void UseUseAsyncConverterTest()
        {
            var cm = new ConverterManager();

            cm.AddConverter <int, string, Attribute>(new UseAsyncConverter());

            var converter = cm.GetConverter <int, string, Attribute>();

            Assert.Equal("12", converter(12, new TestAttribute(null), null));
        }
        public void CatchAll()
        {
            var cm = new ConverterManager(); // empty 
            cm.AddConverter<object, Wrapper>(x => new Wrapper { Value = x.ToString() });

            var func = cm.GetConverter<int, Wrapper, Attribute>();

            var x1 = func(123, null);
            Assert.Equal("123", x1.Value);
        }
        public void ExactMatchOverride()
        {
            var cm = new ConverterManager(); // empty 
            cm.AddConverter<string, string>(x => "*" + x + "*");

            var func = cm.GetConverter<string, string, Attribute>();
                        
            var x1 = func("x", null);
            Assert.Equal("*x*", x1);
        }
示例#17
0
        public MainWindow()
        {
            InitializeComponent();
            Load();
            DataContext = SettingsViewModel;

            ConverterBox.ItemsSource   = Enum.GetValues(typeof(KnownConverter));
            ConverterBox.SelectedIndex = 0;
            _converterManager          = new ConverterManager(SettingsViewModel.KnownTypes);
        }
        public void Identity()
        {
            var cm = new ConverterManager(); // empty 

            var identity = cm.GetConverter<string, string, Attribute>();

            var value = "abc";
            var x1 = identity(value, null);
            Assert.Same(x1, value);
        }
        public void UseGenericAsyncConverterTest()
        {
            var cm = new ConverterManager();

            cm.AddConverter <int, string, Attribute>(typeof(UseGenericAsyncConverter <>));

            var converter = cm.GetSyncConverter <int, string, Attribute>();

            Assert.Equal("12", converter(12, new TestAttribute(null), null));
        }
示例#20
0
        public void Identity()
        {
            var cm = new ConverterManager(); // empty

            var identity = cm.GetConverter <string, string, Attribute>();

            var value = "abc";
            var x1    = identity(value, null);

            Assert.Same(x1, value);
        }
示例#21
0
        public void OpenTypeArray()
        {
            var cm = new ConverterManager();

            cm.AddConverter <OpenType[], string, Attribute>(typeof(OpenArrayConverter <>));
            var attr = new TestAttribute(null);

            var converter = cm.GetConverter <int[], string, Attribute>();

            Assert.Equal("1,2,3", converter(new int[] { 1, 2, 3 }, attr, null));
        }
        public static IConverterManager GetOrCreateConverterManager(this JobHostConfiguration config)
        {
            IConverterManager cm = config.GetService <IConverterManager>();

            if (cm == null)
            {
                cm = new ConverterManager();
                config.AddService <IConverterManager>(cm);
            }
            return(cm);
        }
        public void ClosedTypeArray()
        {
            var cm = new ConverterManager();

            cm.AddConverter <int[], string, Attribute>(new OpenArrayConverter <int>());
            var attr = new TestAttribute(null);

            var converter = cm.GetSyncConverter <int[], string, Attribute>();

            Assert.Equal("1,2,3", converter(new int[] { 1, 2, 3 }, attr, null));
        }
示例#24
0
        public void Inheritence()
        {
            var cm   = new ConverterManager(); // empty
            var func = cm.GetConverter <DerivedWrapper, Wrapper, Attribute>();

            var obj = new DerivedWrapper {
                Value = "x"
            };
            Wrapper x1 = func(obj, null);

            Assert.Same(x1, obj);
        }
示例#25
0
        public void ExactMatchOverride()
        {
            var cm = new ConverterManager(); // empty

            cm.AddConverter <string, string>(x => "*" + x + "*");

            var func = cm.GetConverter <string, string, Attribute>();

            var x1 = func("x", null);

            Assert.Equal("*x*", x1);
        }
示例#26
0
        static void AddAdapter <T>(ConverterManager cm, ICloudBlobStreamBinder <T> x)
        {
            cm.AddExactConverter <Stream, T>(stream => x.ReadFromStreamAsync(stream, CancellationToken.None).Result);

            cm.AddExactConverter <ApplyConversion <T, Stream>, object>(pair =>
            {
                T value       = pair.Value;
                Stream stream = pair.Existing;
                x.WriteToStreamAsync(value, stream, CancellationToken.None).Wait();
                return(null);
            });
        }
示例#27
0
        private static void AddConverterBuilder <TSource, TDestination, TAttribute>(
            this ConverterManager converterManager,
            PatternMatcher patternMatcher)
            where TAttribute : Attribute
        {
            if (converterManager == null)
            {
                throw new ArgumentNullException("converterManager");
            }

            converterManager.AddConverter <TSource, TDestination, TAttribute>(
                (typeSource, typeDest) => patternMatcher.TryGetConverterFunc(typeSource, typeDest));
        }
        public void ObjectToJArray_ChainConverter()
        {
            var jobjString = "{ \"a\": 2 }";
            var obj        = JObject.Parse(jobjString);
            var cm         = new ConverterManager();

            cm.AddConverter <string, IEnumerable <JObject>, Attribute>((str, attr) => new List <JObject>()
            {
                JObject.Parse(str), JObject.Parse(str)
            });
            var jarray = new JArray(obj, obj);

            TestDefaultConverter(jobjString, jarray, cm);
        }
        private T TestDefaultConverter <F, T>(F from, T to, ConverterManager cm = null)
        {
            if (cm == null)
            {
                cm = new ConverterManager();
            }
            var converter = cm.GetSyncConverter <F, T, Attribute>();

            Assert.NotNull(converter);
            var result = converter(from, null, null);

            Assert.Equal(to, result);
            return(result);
        }
示例#30
0
        public void CatchAll()
        {
            var cm = new ConverterManager(); // empty

            cm.AddConverter <object, Wrapper>(x => new Wrapper {
                Value = x.ToString()
            });

            var func = cm.GetConverter <int, Wrapper, Attribute>();

            var x1 = func(123, null);

            Assert.Equal("123", x1.Value);
        }
        public void JObjectMiddleman()
        {
            var cm = new ConverterManager();

            cm.AddConverter <OpenType.Poco, JObject, Attribute>((src, dest) =>
                                                                (input, attr2, ctx) =>
            {
                var val  = JObject.FromObject(input);
                val["c"] = "custom";     // stamp an extra field to verify it's our serialization
                return(Task.FromResult <object>(val));
            });

            cm.AddConverter <JObject, Other>(obj => new Other {
                Value2 = obj["c"].ToString()
            });
            var attr = new TestAttribute(null);

            // Non poco types don't match
            Assert.Null(cm.GetSyncConverter <int, JObject, Attribute>());
            Assert.Null(cm.GetSyncConverter <Object, JObject, Attribute>());

            var converter = cm.GetSyncConverter <Wrapper, JObject, Attribute>();

            Assert.NotNull(converter);

            // Wrapper --> JObject --> Other
            var c2 = cm.GetSyncConverter <Wrapper, Other, Attribute>();

            Assert.NotNull(c2);

            Other result = c2(new Wrapper {
                Value = "x"
            }, null, null);

            Assert.Equal("custom", result.Value2);


            // If we now add a direct converter, that takes precedence
            cm.AddConverter <Wrapper, Other>(input => new Other {
                Value2 = input.Value
            });
            var direct = cm.GetSyncConverter <Wrapper, Other, Attribute>();

            Other result2 = direct(new Wrapper {
                Value = "x"
            }, null, null);

            Assert.Equal("x", result2.Value2);
        }
示例#32
0
        public static IBindingProvider Create(
            INameResolver nameResolver,
            IConverterManager converterManager,
            IStorageAccountProvider storageAccountProvider,
            IExtensionTypeLocator extensionTypeLocator,
            IContextGetter <IMessageEnqueuedWatcher> messageEnqueuedWatcherGetter,
            IContextGetter <IBlobWrittenWatcher> blobWrittenWatcherGetter,
            IExtensionRegistry extensions)
        {
            List <IBindingProvider> innerProviders = new List <IBindingProvider>();

            if (converterManager == null)
            {
                converterManager = new ConverterManager();
            }

            // Wire up new bindings
            var ruleQueueOutput = QueueBindingProvider.Build(storageAccountProvider, messageEnqueuedWatcherGetter, nameResolver, converterManager);

            innerProviders.Add(ruleQueueOutput);

            innerProviders.Add(new BlobAttributeBindingProvider(nameResolver, storageAccountProvider, extensionTypeLocator, blobWrittenWatcherGetter));
            innerProviders.Add(TableAttributeBindingProvider.Build(nameResolver, converterManager, storageAccountProvider, extensions));

            // add any registered extension binding providers
            foreach (IBindingProvider provider in extensions.GetExtensions(typeof(IBindingProvider)))
            {
                innerProviders.Add(provider);
            }

            innerProviders.Add(new CloudStorageAccountBindingProvider(storageAccountProvider));
            innerProviders.Add(new CancellationTokenBindingProvider());

            // The TraceWriter binder handles all remaining TraceWriter/TextWriter parameters. It must come after the
            // Blob binding provider; otherwise bindings like Do([Blob("a/b")] TextWriter blob) wouldn't work.
            innerProviders.Add(new TraceWriterBindingProvider());

            ContextAccessor <IBindingProvider> bindingProviderAccessor = new ContextAccessor <IBindingProvider>();

            innerProviders.Add(new RuntimeBindingProvider(bindingProviderAccessor));
            innerProviders.Add(new DataBindingProvider());

            IBindingProvider bindingProvider = new CompositeBindingProvider(innerProviders);

            bindingProviderAccessor.SetValue(bindingProvider);
            return(bindingProvider);
        }
        internal void Initialize(IBindingProvider bindingProvider, ConverterManager converter, IExtensionRegistry extensionRegistry)
        {
            foreach (var extension in extensionRegistry.GetExtensions <IExtensionConfigProvider>())
            {
                this.AddExtension(extension);
            }

            this._root = bindingProvider;

            // Populate assembly resolution from converters.
            if (converter != null)
            {
                converter.AddAssemblies((type) => this.AddAssembly(type));
            }

            AddTypesFromGraph(bindingProvider as IBindingRuleProvider);
        }
示例#34
0
        public void AllTest()
        {
            var buffer = nameof(ConverterManagerTests).FromEncodingString();

            IAlgorithmConverter converter = ConverterManager.GetAlgorithm <Base32StringConverter>();
            var algorithm = converter.ConvertTo(buffer);

            Assert.True(buffer.SequenceEqual(converter.ConvertFrom(algorithm)));

            converter = ConverterManager.GetAlgorithm <Base64StringConverter>();
            algorithm = converter.ConvertTo(buffer);
            Assert.True(buffer.SequenceEqual(converter.ConvertFrom(algorithm)));

            converter = ConverterManager.GetAlgorithm <HexStringConverter>();
            algorithm = converter.ConvertTo(buffer);
            Assert.True(buffer.SequenceEqual(converter.ConvertFrom(algorithm)));
        }
示例#35
0
        // We can remove this when we fix https://github.com/Azure/azure-webjobs-sdk/issues/995

        // create IConverterManager adapters to any legacy ICloudBlobStreamBinder<T>.
        static void AddStreamConverters(IExtensionTypeLocator extensionTypeLocator, ConverterManager cm)
        {
            if (extensionTypeLocator == null)
            {
                return;
            }

            foreach (var type in extensionTypeLocator.GetCloudBlobStreamBinderTypes())
            {
                var instance = Activator.CreateInstance(type);

                var bindingType = Blobs.CloudBlobStreamObjectBinder.GetBindingValueType(type);
                var method      = typeof(JobHostConfigurationExtensions).GetMethod("AddAdapter", BindingFlags.Static | BindingFlags.NonPublic);
                method = method.MakeGenericMethod(bindingType);
                method.Invoke(null, new object[] { cm, instance });
            }
        }
        public void AttributeOverloads2()
        {
            var cm = new ConverterManager(); // empty 
            cm.AddConverter<Wrapper, string, TestAttribute>((x, attr) => string.Format("[t1:{0}-{1}]", x.Value, attr.Flag));
            cm.AddConverter<Wrapper, string>(x => string.Format("[common:{0}]", x.Value));
                        
            // This has an exact match on attribute and gives the specific function we registered.
            var func1 = cm.GetConverter<Wrapper, string, TestAttribute>();
            Assert.NotNull(func1);
            var x1 = func1(new Wrapper { Value = "x" }, new TestAttribute("y"));
            Assert.Equal("[t1:x-y]", x1);

            // Nothing registered for this attribute, so we return the converter that didn't require any attribute.
            var func2 = cm.GetConverter<Wrapper, string, TestAttribute2>();
            Assert.NotNull(func2);
            var x2 = func2(new Wrapper { Value = "x" }, new TestAttribute2("y"));
            Assert.Equal("[common:x]", x2);
        }
        public void AttributeOverloads()
        {
            var cm = new ConverterManager(); // empty 
            cm.AddConverter<Wrapper, string, TestAttribute>((x, attr) => string.Format("[t1:{0}-{1}]", x.Value, attr.Flag));
            cm.AddConverter<Wrapper, string, TestAttribute2>((x, attr) => string.Format("[t2:{0}-{1}]", x.Value, attr.Flag));

            // Since converter was registered for a specific attribute, it must be queried by that attribute. 
            var funcMiss = cm.GetConverter<Wrapper, string, Attribute>();
            Assert.Null(funcMiss);

            // Each attribute type has its own conversion function
            var func1 = cm.GetConverter<Wrapper, string, TestAttribute>();
            Assert.NotNull(func1);
            var x1 = func1(new Wrapper { Value = "x" } , new TestAttribute("y"));
            Assert.Equal("[t1:x-y]", x1);

            var func2 = cm.GetConverter<Wrapper, string, TestAttribute2>();
            Assert.NotNull(func2);
            var x2 = func2(new Wrapper { Value = "x" }, new TestAttribute2("y"));
            Assert.Equal("[t2:x-y]", x2);
        }
        public void JsonSerialization()
        {
            var cm = new ConverterManager(); // empty             
            
            cm.AddConverter<string, Wrapper>(str => new Wrapper { Value = str });

            var objSrc = new Other { Value2 = "abc" };

            // Json Serialize: (Other --> string)
            // custom          (string -->Wrapper)
            var func = cm.GetConverter<Other, Wrapper, Attribute>();
            Wrapper obj2 = func(objSrc, null);

            string json = obj2.Value;
            var objSrc2 = JsonConvert.DeserializeObject<Other>(json);
            Assert.Equal(objSrc.Value2, objSrc2.Value2);            
        }