编辑:我刚刚意识到我想要做的是遵循我从Mark Seemann学到的依赖注入模式,该模式在该主题上写了excellent book。我想有一个方法,我做一些设置,如添加行,但传入一个将行写入上下文的对象。 BulkInsert方法适用于大型"设置"而AddRange适用于较小的设置。
我有一个静态方法,我在我的DbContext中传递,并且我将行更新为多个实体。根据我调用方法的方式,我想使用BulkInsert
或AddRange
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类,因此我在调用端设置的任何函数都需要接受通用列表(是吗?)因为我不想为每种可能的类型传递一个函数。
ETA:
BulkInsert和AddRange都是通过EntityFramework添加行。他们每人都拿一份清单。 但 BulkInsert有一个可选的选项参数,因此可以调用context.BulkInsert(myList, opts)
答案 0 :(得分:3)
我认为你需要的只是一个接受IList
的代表,但如果不知道AddRange
和AddBulk
方法的签名就很难知道
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);
答案 1 :(得分:1)
我很想过我是否应该发布它(因为它有点回答问题,但我不认为它解决了背后的问题)但是就这样吧:
如果你知道你将要使用的所有可能的类型,最简单的方法是:
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
的情况下进行动态调度......但我不知道不太喜欢那些 - 如果你对此感兴趣的话,那么an example where this trick is used
答案 2 :(得分:0)
如果Foo和Bar共享一个公共接口,那么您可以使用Action delegate传递该方法。
例如:
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);
}