简体   繁体   中英

C# - Define a dictionary of generic functions

How do i define a dictionary that maps a Type to a function that takes this type as input

Something like:

var stringifiers = new Dictionary<Type, Func<T, string>> {
        { typeof(string), s => s},
        { typeof(float), f => f.ToString()},
        { typeof(bool), b => b.ToString()},
    };

usage :

stringifiers[bar.getType()](bar)

The dictionary definition above does not compile obviously

The type on namespace 'T' counld not be found

If you're not stuck on the dictionary and you want a one to one relationship between the type and the function, you can use generic static variables to store and retrieve the functions and gain type safety in the process.

The "magic" occurs in StringInternal<T> . Because StringInternal<string>.Stringify is a different variable from StringInternal<float>.Stringify , you can store a Func in that static variable and access it using the type.

The Stringifier class is a non-generic class with generic functions so that we can use type inference, simplifying our calling syntax.

public static class Stringifier
{
    public static void Set<T>(Func<T, string> func)
    {
        StringifierInternal<T>.Stringify = func;
    }

    public static string Stringify<T>(T value)
    {
        return StringifierInternal<T>.Stringify(value);
    }

    private static class StringifierInternal<T>
    {
        public static Func<T, string> Stringify { get; set; }
    }
}

Usage:

Stringifier.Set<string>(v => v + "stringified");
Stringifier.Set<float>(v => v.ToString() + "floatstringified");
Stringifier.Set<bool>(v => v ? "it's twoo" : "not twoo");

Console.WriteLine(Stringifier.Stringify("X"));
Console.WriteLine(Stringifier.Stringify((float)17));
Console.WriteLine(Stringifier.Stringify(true));

Output:

Xstringified
17floatstringified
it's twoo

Try this class:

public class Stringifier
{
    private Dictionary<Type, Delegate> _store
        = new Dictionary<Type, Delegate>();

    public void Store<T>(Func<T, string> value)
    {
        _store[typeof(T)] = value;
    }

    public Func<T, string> Fetch<T>()
    {
        return (Func<T, string>)_store[typeof(T)];
    }

    public string Fetch<T>(T value)
    {
        return this.Fetch<T>().Invoke(value);
    }

    public string Fetch(Type type, object value)
    {
        return (string)
        (
            typeof(Stringifier)
                .GetMethods()
                .Where(x => x.Name == "Fetch")
                .Where(x => x.IsGenericMethod)
                .Where(x => x.ReturnType == typeof(string))
                .Select(x => x.MakeGenericMethod(type))
                .First()
                .Invoke(this, new [] { value })
        );
    }       
}

Then you can do this:

var stringifier = new Stringifier();

stringifier.Store<string>(s => $"!{s}!");
stringifier.Store<float>(f => f.ToString());
stringifier.Store<bool>(b => b.ToString());

var bar = "XXX";

var value = stringifier.Fetch(bar.GetType(), bar);

Console.WriteLine(value);   

The output I get is !XXX! .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM