我将API定义为接口,我们称之为IFoo
,我想定义一个方法Bar()
此方法Bar()
将获取一个必需参数,然后是一些任意数量的其他参数。对这些其他论点的解释将取决于IFoo
对于这种情况,使用params
或使用Dictionary<String, Object>
来定义我的界面更合适。
public interface IFoo
{
bool Bar(String id, params Object[] params);
}
或者
public interface IFoo
{
bool Bar(String id, Dictionary<String, Object> params);
}
用户似乎更容易调用前者,但后者在其意图中更明确,因为对于前者,您必须按照特定顺序指定参数,以便实现正确解释它们你基本上是在做命名参数。
所以问题:
为了记录,我知道.Net 4.0中的named parameters但是这个代码需要在.Net 3.5上编译,所以不能使用任何.Net 4.0+功能
只是为了添加更多有关我的IFoo
和Bar()
方法实际代表的内容的详细信息,因为有人问过。
IFoo
代表一些存储子系统,Bar()
实际上是一个创建操作。根据存储子系统Bar()
可能不需要ID以外的任何参数,或者它可能需要许多参数。
所以回应@Kirk Woll的评论和@ Fernando的回答这里有更多的信息。
我可能永远不会自己调用IFoo.Bar()
,这个界面是开源框架的一部分。第三方开发人员将实现IFoo
,最终用户将调用它的特定实例,让IFoo
根本就是让用户更容易在存储子系统之间迁移他们的应用程序,因为他们可以代码到接口而不是特定的实现尽可能的人。
在最简单的情况下,底层存储子系统只有一种形式的存储,因此除了ID之外不需要任何参数。在复杂的情况下,存储子系统可以允许多种类型的存储,并且每种类型的存储可以允许任意复杂的一组配置参数,例如,索引大小,持久性,事务行为,索引策略,安全性和ACL考虑因素等。
我同意@Fernando可能更多的多态性可能有意义,也许多态性与泛型和类型限制相结合可能是最好的。例如。
public interface IFoo
{
bool Bar<T>(T parameters) where T : IBarConfig;
}
public interface IBarConfig
{
String ID { get; set; }
}
然后使用类似的实现:
public class MyFoo
{
bool Bar<T>(T config) where T : MyBarConfig
{
//Implementation
}
}
public class MyBarConfig : IBarConfig
{
public String ID { get; set; }
public long IndexSegmentSize { get; set; }
//Etc...
}
这不是我的头脑,所以不确定在Bar()
中定义MyFoo
与其实现的接口有不同的类型限制是否合法?
答案 0 :(得分:4)
您需要决定是否需要搜索或能够从params集合/数组中检索对象。
使用Object[] params
时,对象上没有索引。您需要迭代整个集合以查找项目(通过其键)。
使用Dictionary<String, Object>
时,您的对象会被其键标记,并且按键始终可以轻松搜索/查询。
根据您的需要,您需要决定您的方法。
字典搜索速度更快,但创建索引会产生开销。
答案 1 :(得分:2)
params提供更容易编写/读取代码。即每次调用String.Format时,映像构造字典 - 代码将是不可读的。另一方面,如果你已经有参数字典 - 可以使用它。
我建议您重新考虑API,看看您是否可以接受IEnumerable
,甚至更好IEnumerable<T>
作为参数。不幸的是,对于这样的通用IFoo样本名称,不可能看出这种方法是否有效。
答案 2 :(得分:1)
词典方法还有另一个问题:拼写错误。你可能需要定义很多常量来作为关键来避免这个问题。
为什么不选择多态解?
public interface IFoo {
void Bar(FooData data);
}
public abstract class FooData {
public int Id {get;set;}
}
public class MyFooData1 : FooData {
public string SomeProperty {get;set;}
//...
}
public class MyFoo : IFoo {
public void Bar(FooData data) {
var myData = (MyFooData1)data;
//...
}
}
public class MyFooData2 : FooData {
public int SomeOtherProperty {get;set;}
//...
}
public class MyFoo2 : IFoo {
public void Bar(FooData data) {
var myData = (MyFooData2)data;
//...
}
}
你最终会得到更多更小的课程,但它们很容易测试和扩展。
<强>更新强>
@RobV如果你正在实现一个接口,你不能改变类型限制,但是,如果你将你的type参数放在接口声明中,你可以完成你想要做的事情:
public interface IFoo<T> where T : IBarConfig {
void Bar(T parameters);
}
public class MyBarConfig: IBarConfig {
public String ID { get; set; }
public long IndexSegmentSize { get; set; }
}
public class MyFoo : IFoo<MyBarConfig> {
public void Bar(MyBarConfig config) {
//Implementation
}
}
答案 3 :(得分:0)
我应该使用哪种形式(以及为什么?) - 这些被认为是最佳实践之一吗? ---&GT;你应该使用第二个,因为它比第二个更容易出错。
关于替代模式,肯定有一种方法可以更好地实现这一点。你能告诉我们你的问题究竟是什么吗?而不是使用IFoo和Bar?除非我确切地知道你要做什么,为什么......
,否则我无法提出任何建议答案 4 :(得分:0)
你提到可选参数这一事实让我觉得IDictionary<string,object>
方法会更好 - 这是你在.Net 3.5中提供这种界面的最佳方法。你可以只是询问对象并做一些类似于MVC为htmlAttributes所做的事情(使用反射将匿名对象转换为IDictionary<string,object>
)。
我更喜欢params object[]
方法的情况是那些试图在每种情况下给它们起名字的情况只是奇怪/不可能,比如string.format
。