C#中是否可以选择性地要求一个可选参数



C#中是否有可能在特定情况下需要一个可选参数,并在编译时引发错误?

让我以下面的代码为例进行解释。类ServiceResponse具有接受枚举值和可选字符串的构造函数。如果用于实例化类的枚举值等于Error,则需要该消息。在示例代码中,当没有提供消息时,它将抛出一个ArgumentNullException。遗憾的是,这只会在运行时可见。但是,它应该在编译时变得可见,因此它会警告开发人员。

public class ServiceResponse
{
public ServiceResponse(ServiceResult result, string message = null)
{
Result = result;
Message = result == ServiceResult.Error ? message ?? throw new System.ArgumentNullException(nameof(message)) : message;
}
public string Message { get; }
public ServiceResult Result { get; }
}
public enum ServiceResult {
Ok,
NotFound,
Error
}

我将使构造函数私有化,并公开实例化所需的3个静态方法。

您也可以将CreateError(message)中的message字段设置为NotNull,一些linter会发现这一点并将其视为警告。

public class ServiceResponse
{
// Change constructor to private
private ServiceResponse(ServiceResult result, string message)
{
Result = result;
Message = message;
}
public static ServiceResponse CreateOk(string message = null)
{
return new ServiceResponse(ServiceResult.OK, message);
}
public static ServiceResponse CreateNotFound(string message = null)
{
return new ServiceResponse(ServiceResult.NotFound, message);
}
public static ServiceResponse CreateError([NotNull] string message)
{
if (string.IsNullOrEmpty(message))
{
throw new ArgumentNullException(nameof(message));
}
return new ServiceResponse(ServiceResult.Error, message);
}
... Other Class Properties
}

是否可以选择静态创建方法?

public class ServiceResponse
{
private ServiceResponse(ServiceResult result, string message = null)
{
Result = result;
Message = message;
}
public string Message { get; }
public ServiceResult Result { get; }
public static ServiceResponse CreateInfo(ServiceResult result, string message = null)
{
return new ServiceResponse(result, message);
}
public static ServiceResponse CreateError(string message)
{
return new ServiceResponse(ServiceResult.Error, message);
}
}

这并不能阻止将null传递给CreateError,但开发人员可能不会意外地错过消息。

OneOf库可能会在这里提供帮助。

public abstract class ServiceResponse
: OneOfBase<
ServiceResponse.OkResult,
ServiceResponse.NotFoundResult,
ServiceResponse.ErrorResult>
{
public class OkResult : ServiceResponse
{
}
public class NotFoundResult : ServiceResponse
{    
}
public class ErrorResult : ServiceResponse
{
public string Message { get; }
}
}

用法A

ServiceResponse result = ...;
if (result is ServiceResponse.OkResult ok)
...;
else if(result is ServiceResponse.ErrorResult error)
...;

用法B

ServiceResponse result = ...;
result.Match( 
ok => ...,
notFound => ...,
error => ...);

您有一个带有类型的枚举。将其转换为具有相同接口(基类(的特定对象

public abstract class ServiceResponse
{
public ServiceResponse(ServiceResult result, string message = null)
{
Result = result;
Message = result == ServiceResult.Error ? message ?? throw new System.ArgumentNullException(nameof(message)) : message; //questionable logic
}
public string Message { get; }
public ServiceResult Result { get; }
}
public class OkServiceResponse : ServiceResponse
{
public OkServiceResponse():base(ServiceResult.Ok){}
}
public class NotFoundServiceResponse : ServiceResponse
{
public NotFoundServiceResponse(string message):base(ServiceResult.NotFound, message){}
}
public class ErrorServiceResponse : ServiceResponse
{
public ErrorServiceResponse(string message):base(ServiceResult.Error, message){}
}

最新更新