C#使用Dictionary和Func

问题描述

我想知道是否可以使用字典在给定某种解析器的情况下创建该类型的新实例,其中新类型具有构造函数args。本质上是工厂方法

我有一些可行的方法,尽管我希望找到一种更清洁的方法。我遇到了Java中的问题,并认为这在C#中很容易-也许不是!

所以它基于给定的字典:

Dictionary<Type,Func<ToResolve,Resolved>>

具有给定类型的解析器Func<ToResolve,Resolved>。我想从ToResolve映射以解析将ToResolve字段传递给ToResolve构造函数参数。 ToResolveResolve是该场景的抽象类。 ToResolve in,ToResolve out。

因此,工作方案是:

Dictionary<Type,Resolved>> map = new Dictionary<Type,Resolved>>
{
    {
        typeof(ToResolve1),r =>
        {
            var tr = (ToResolve1) r;
            return new Resolved1(tr.x);
        }
    },{
        typeof(ToResolve2),r =>
        {
            var tr = (ToResolve2) r;
            return new Resolved2(tr.x);
        }
    }
};

这可以称为:

var toResolve1 = new ToResolve1(100);
var resolved1 = map[toResolve1.GetType()];

var toResolve2 = new ToResolve2("some string");
var resolved2 = map[toResolve2.GetType()];

使用简单的类声明为:

public abstract class Resolved { }

public class Resolved1 : Resolved
{
    public readonly int x;

    public Resolved1(int x) => this.x = x;
}

public class Resolved2 : Resolved
{
    public readonly string x;

    public Resolved2(string x) => this.x = x;
}

public abstract class ToResolve { }

public class ToResolve1 : ToResolve
{
    public readonly int x;

    public ToResolve1(int x) => this.x = x;
}

public class ToResolve2 : ToResolve
{
    public readonly string x;

    public ToResolve2(string x) => this.x = x;
}

是否有更简洁的方法?理想情况下,不必将lambda包装在两行上并使用显式转换。

并且不使用AutoMapper

解决方法

看起来您只需要一堆重载方法,不确定这是您想要的一种简洁方法吗?

public static class Resolver
{
    public static Resolved1 Resolve(ToResolve1 r) => new Resolved1(r.x);
    public static Resolved2 Resolve(ToResolve2 r) => new Resolved2(r.x);
}

var resolved1 = Resolver.Resolve(new ToResolve1(100));
var resolved2 = Resolver.Resolve(new ToResolve2("some string"));
,

字典不支持通用值,但是,您可以编写自己的自定义字典:

class ResolverDictionary
{
    static class Resolver<T> where T : ToResolve
    {
        public static Func<T,Resolved> Instance;
    }
    
    public ResolverDictionary Add<T>(Func<T,Resolved> resolver) where T : ToResolve
    {
        Resolver<T>.Instance = resolver;
        return this;
    }
    
    public Func<T,Resolved> Get<T>() where T : ToResolve
    {
        return Resolver<T>.Instance;
    }
}

可用于以下用途:

var dictionary = new ResolverDictionary()
    .Add((ToResolve1 r) => new Resolved1(r.x))
    .Add((ToResolve2 r) => new Resolved2(r.x));
    
var resolver1 = dictionary.Get<ToResolve1>();
var resolved1 = resolver1(new ToResolve1(100));
,

我相信您可以通过按原样保留字典,但添加单独的方法在其中添加条目来完成您想要的事情,

static class Resolver {
    private static readonly Dictionary<Type,Func<ToResolve,Resolved>> _map = new Dictionary<Type,Resolved>>();

    static Resolver() {
        Add((ToResolve1 tr) => new Resolved1(tr.x));
        Add((ToResolve2 tr) => new Resolved2(tr.x));
    }

    private static void Add<TToResolve,TResolved>(Func<TToResolve,TResolved> func) where TToResolve : ToResolve where TResolved : Resolved {
        _map[typeof(TToResolve)] = x => func((TToResolve) x);
    }

    // the only public interface,non-generic
    public static Resolved Resolve(ToResolve x) {
        return _map[x.GetType()](x);
    }
}