Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 扩展接口签名而无需在多个位置编辑代码_C#_Oop_Design Patterns_Interface - Fatal编程技术网

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");
}