如何使用泛型类型传入要调用的方法的函数?

本文关键字:方法 函数 调用 何使用 泛型类型 | 更新日期: 2023-09-27 18:05:57

编辑:我刚刚意识到我想做的是遵循依赖注入模式,这是我从Mark Seemann那里学到的,Mark Seemann写了一本关于这个主题的优秀的书。我想有一个方法,我做一些设置,比如添加行,但传入一个对象,写入行到上下文。BulkInsert方法用于大型"设置",而adrange方法用于小型设置。

我有一个静态方法,我在我的DbContext传递,我更新行到几个实体。根据我调用方法的方式,我想使用BulkInsertAddRange

添加行
public static void MySetup(MyContext, int addMethod)
{
    var list1 = new List<Foo>{......}
    if (addMethod = 1)
       context.BulkInsert(list1);
    else
       context.AddRange(list1);
    var list2 = new List<Bar>{......}
    if (addMethod = 1)
       context.BulkInsert(list2);
    else
       context.AddRange(list2);
}

我想学习如何传入一个函数,而不是传入一个变量,所以它像这样:

public static void MySetup(MyContext context, ??? myAdd)
{
    var list1 = new List<Foo>{......}
    myAdd(context, list1);
    var list2 = new List<Bar>{......}
    myAdd(context, list2);
}

认为我正在寻找的是一个委托。请注意,我使用了不同类型的List类,所以我在调用端设置的任何函数都需要接受泛型列表(是吗?),因为我不想为每种可能的类型传递一个函数。

埃塔:

BulkInsert和AddRange都是通过EntityFramework添加行。他们每人拿一张单子。然而, BulkInsert有一个可选的选项参数,所以它可能被称为context.BulkInsert(myList, opts)

如何使用泛型类型传入要调用的方法的函数?

认为您所需要的只是一个接受IList的代表,但如果不知道AddRangeAddBulk方法的签名,则很难知道。

public static void MySetup(MyContext context, Action<MyContext, IList> myAdd)
{
    var list1 = new List<Foo> { };
    myAdd(context, list1);
    var list2 = new List<Bar> { };
    myAdd(context, list2);
}
...
Action<MyContext, IList> insertRange = (context, list) =>
{
    context.AddRange(list);
};
Action<MyContext, IList> insertBulk = (context, list) =>
{
    context.BulkInsert(list);
};
MySetup(new MyContext(), insertRange);
// or...
MySetup(new MyContext(), insertBulk);

我想了很久我是否应该发布它(因为它确实回答了问题,但我不认为它解决了背后的问题),但它是:

如果你事先知道所有可能使用的类型,最简单的方法是:

interface IAddStuff 
{
    void Add (MyContext context, IList<Foo> list);
    void Add (MyContext context, IList<Bar> list);
}
class Operations
{
    public static void MySetUp(MyContext context, IAddStuff adder)
    {
        var list1 = new List<Foo> ();
        adder.Add (context, list1);
        var list2 = new List<Bar> ();
        adder.Add (context, list2);
    }
}
class SampleImplementation : IAddStuff 
{
    public void Add(MyContext context, IList<Foo> list)
    {
        // ...
    }
    public void Add(MyContext context, IList<Bar> list)
    {
        // ...
    }
}

现在,如果你不知道确切的情况,你仍然可以做运行时调度(并让实现决定):

class MyContext {}
class Foo {}
class Bar {}
interface IAddStuff 
{
    void Add<T> (MyContext context, IList<T> list);
}
class Operations
{
    public static void MySetUp(MyContext context, IAddStuff adder)
    {
        var list1 = new List<Foo> ();
        adder.Add (context, list1);
        var list2 = new List<Bar> ();
        adder.Add (context, list2);
    }
}
class SampleImplementation : IAddStuff 
{
    public void Add<T> (MyContext context, IList<T> list)
    {
        if (typeof(T) == typeof(Foo)) 
            AddFoo(context, list.Cast<Foo>());
        else if (typeof(T) == typeof(Bar)) 
            AddBar(context, list.Cast<Bar>());
    }
    void AddFoo(MyContext context, IEnumerable<Foo> list)
    {
        // ...
    }
    void AddBar(MyContext context, IEnumerable<Bar> list)
    {
        // ...
    }
}
现在您可以看到,您只将问题(运行时检查您真正拥有哪种泛型类型)移动到上述接口的实现中,但是可以使其他代码更干净。

不知道你是否觉得这有用,但这是最接近我认为你问

PS应该很明显,你可以用一些参数来更新它,以判断是否应该使用bulk-insert

PPS是的,你可以滥用 dynamic的东西来获得动态调度没有if s…但是我不太喜欢这些如果你对它感兴趣的话这里有一个使用技巧的例子

如果Foo和Bar共享一个公共接口,那么你可以使用Action委托传递该方法。

例如

:

public interface IBaz
{
}
public class Foo : IBaz
{     
}
public class Bar : IBaz
{
}
public static void MySetup(DurianContext context, Action<DurianContext, List<IBaz>> addMethod)
{            
    List<IBaz> list1 = new List<IBaz>();
    addMethod(context, list1);
    List<IBaz> list2 = new List<IBaz>();
    addMethod(context, list2);
}