C# 扩展接口签名而无需在多个位置编辑代码
我有一个接口和实现此接口的现有代码:C# 扩展接口签名而无需在多个位置编辑代码,c#,oop,design-patterns,interface,C#,Oop,Design Patterns,Interface,我有一个接口和实现此接口的现有代码: public interface IBusinessService<T> where T : class { Task Add(T category); Task Delete(T category); Task Update(T category); Task<IEnumerable<T>> GetAll(); Task<T> GetById(int id);
public interface IBusinessService<T> where T : class
{
Task Add(T category);
Task Delete(T category);
Task Update(T category);
Task<IEnumerable<T>> GetAll();
Task<T> GetById(int id);
}
所以我们需要id
参数可以是Guid
的类型。如果可能,这将是理想的:
public interface IBusinessService<T> where T : class
{
/* ... the other code is omitted for the brevity */
Task<T> GetById(Guid or int id );
}
但是如果我要这样做,那么我需要编辑这么多代码。因此,这似乎不是一个好的解决方案
有没有一种方法可以在不破坏更改的情况下将另一种类型的
id
添加到接口方法GetById
中?这似乎首先是一个设计问题(接口/API设计)。从一开始就应该清楚ID是由Guid
表示还是由原始int
值表示。但不是两者都有。通常,您尝试使用协议来控制客户机-服务器通信,或者至少通过定义服务器API来控制通信。该协议将定义API期望的值,客户机必须注意以正确的格式输入这些值
考虑使用int
ID,并在需要时使用从Guid
到int
的自定义转换。或者引入一个表(Dictionary
),用于存储Guid
和int
值对。因此,对于每个进入应用程序的Guid
,您将在内部生成一个整数,该整数将替换Guid
。但是必须有一些约束或算法来保证ID的唯一性,特别是在使用int
值时。但是我假设当您使用int
作为唯一ID时,您已经有了生成这些ID的算法
向接口添加成员始终是一项突破性的更改
由于您没有使用C#8,因此无法使用新的默认接口方法特性
因此,如果您可以接受突破性的更改,那么您可以重构接口,为id
参数多取一个通用参数。您还可以将
id
参数的类型从int
更改为object
。但这也会带来装箱/拆箱的成本(以便将int
等值类型转换为object
)。我个人认为使用对象
或字符串
都是最好的。我不知道您的web界面,但string
可能是首选的ID类型
因此,如果您不能接受这些破坏性的更改,最好的解决方案是实现一个新的接口,例如,iguiddbusinessservice
:
公共接口iguiddbusinessservice:IBusinessService其中T:class
{
任务GetByGuid(Guid id);
}
实现接口:
public class MyClass : IGuidIdBusinessService<object>
{
#region Implementation of IBusinessService<object>
...
// Either throw NotSupportedException or implement conversion
public async Task<object> GetById(int id)
{
Guid guid = ConvertIntToGuid(id);
return GetByGuid(guid);
}
#endregion
#region Implementation of IGuidIdBusinessService<object>
public async Task<object> GetByGuid(Guid id) => throw new NotImplementedException();
#endregion
}
public类MyClass:iguiddbusinessservice
{
#IBusinessService的区域实现
...
//抛出NotSupportedException或实现转换
公共异步任务GetById(int id)
{
Guid=ConvertIntToGuid(id);
返回GetByGuid(guid);
}
#端区
#iguiddbusinessservice的区域实现
公共异步任务GetByGuid(Guid id)=>抛出新的NotImplementedException();
#端区
}
我真的看不出问题有你描述的那么严重--“但是如果我要这么做,那么我需要编辑这么多代码”
您有多少个实现。20? 关键点在这里,实现与使用。用法可以很多,也可以很多
看起来您的目标是保持使用完整
var id = Guid.NewGuid();
var result = someInst.GetById(id);
// or
var id = 5;
var result = someInst.GetById(id);
没问题,您需要最少的更改。这种情况经常发生
public interface IBusinessService<T> where T : class
{
Task<T> GetById(object id); // NOTE - change to 'object'
}
因此,变化很小。用途将保持不变。没有什么异常。如果使用最新的C#8,则可以使用默认接口实现。您还可以尝试使用一个基本的抽象类来实现它,如果它对您来说是有效的选项,那么如果id是
int
还是guid
,那么为什么两者都有呢?如果它真的有关系,你显然需要两个重载。而且int
和guid
之间不存在转换。唯一的解决方法是使用对象
。这就是通用化的问题。@CSharpie不,我只需要一种方法,但是id
的类型有时可以是Guid
或int
@Learner为什么你认为你需要一种方法?@PavelAnikhouski感谢你的回答。但是,我们使用的是C#6.0。基本抽象类是否允许更改派生类中的参数类型?
public class MyClass : IGuidIdBusinessService<object>
{
#region Implementation of IBusinessService<object>
...
// Either throw NotSupportedException or implement conversion
public async Task<object> GetById(int id)
{
Guid guid = ConvertIntToGuid(id);
return GetByGuid(guid);
}
#endregion
#region Implementation of IGuidIdBusinessService<object>
public async Task<object> GetByGuid(Guid id) => throw new NotImplementedException();
#endregion
}
var id = Guid.NewGuid();
var result = someInst.GetById(id);
// or
var id = 5;
var result = someInst.GetById(id);
public interface IBusinessService<T> where T : class
{
Task<T> GetById(object id); // NOTE - change to 'object'
}
public Task<T> GetById(object id)
{
if (id is int i)
return ProcessIdAsInt<T>(i);
else if (id is Guid g)
return ProcessIdAsGuid<T>(g);
else
throw new InvalidOperationException("Supplied data type not supported");
}