C# 使用 Dictionary 和 Func 创建一个带有 ctor args 的新实例

C# create a new instance with ctor args using a Dictionary and Func

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

我有一些有用的东西,尽管我希望有一种更简洁的方法来做到这一点。我在 Java 中遇到了问题,并认为这在 C# 中很容易 - 也许不是!

所以它基于给定的字典:

Dictionary<Type, Func<ToResolve, Resolved>>

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

所以工作场景是:

Dictionary<Type, Func<ToResolve, Resolved>> map = new Dictionary<Type, Func<ToResolve, 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()];

简单的 class 声明为:

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, Func<ToResolve, 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);
    }
}