繁体   English   中英

将方法转换为通用和非通用类

[英]Casting a method to generic and non generic class

我想具体一点。 我有一个名为Result的类,以及一个从该类派生的类Result

public class Result
{
    public string Message { get; set; }

    public bool Success { get; set; }
}

public class Result<T> : Result
{
    public T Data { get; set; }
}

这些类在方法中用作返回类型。 为此,我制作了此帮助器类:

public class ResultManager
{
    /// <summary>
    /// Returns a success action
    /// </summary>
    public static Result Success()
    {
        var result = new Result { Success = true };

        return result;
    }

    /// <summary>
    /// Returns a success action
    /// </summary>
    /// <typeparam name="T">The object type to return with the result</typeparam>
    public static Result<T> Success<T>(T data)
    {
        var result = new Result<T> { Success = true, Data = data };

        return result;
    }

    /// <summary>
    /// Returns a failed result
    /// </summary>
    public static Result Failed(string errorMessage = null, Exception exception = null)
    {
        // ... unrelevant code for the question

        return new Result { Success = false, Message = errorMessage };
    }
}

如您所见,上面的代码有两种成功的返回类型,一种是如果您不希望返回任何内容,另一种是如果您希望返回某些内容,但是失败的结果将永远不会返回任何内容。 不必要,只有一条错误消息。 这使我想到以下几点:当我想创建一个可以使用返回类型返回成功的方法而没有返回类型的方法失败时, 如何转换它以确定返回类型是成功(通用)还是失败? 像这里这样的方法:

// The return type of the method is Result, because Result<T> derives from it
public static Result GetClipboardFromDateTime(DateTime dateTime)
{
    // Search for items
    IEnumerable<ClipboardCopy> items = null;
    try
    {
        items = mClipboardCollection.Where(a => a.CopiedTime == dateTime);
    }
    catch (Exception ex)
    {
        // This will return the class "Result"
        return ResultManager.Failed(
            "Something went wrong getting copies from the clipboard.", ex);
    }

    // If there is not values
    if (items.Count() <= 0)
        return ResultManager.Failed("There are not copies with that datetime.");

    // Return values
    // This will return the class Result<T>
    return ResultManager.Success(items.ToArray());
}

实际上,我正在这样做:

var clipboard2 = (Result<ClipboardCopy[]>)AClipboard.GetClipboardFromDateTime(DateTime.Today);

如果返回类型为Result(generic),但是返回类型为Return,它将崩溃,但会发生以下异常:

System.InvalidCastException:'无法将类型'AdvancedClipboard.Desktop.Models.Result'的对象转换为类型'AdvancedClipboard.Desktop.Models.Result'1 [AdvancedClipboard.Desktop.Models.ClipboardCopy []]'。

您正在尝试先转换问题。 方法返回两种类型的结果。

  1. 成功
  2. 失败

我认为您应该做这样的事情。

var result = AClipboard.GetClipboardFromDateTime(DateTime.Today);

if(Result.Success)
{
   var dataResult = (Result<ClipboardCopy[]>) result;
}

如果您不想铸造。 还有另一种方法,但我不建议。

var result = AClipboard.GetClipboardFromDateTime(DateTime.Today);

if(result.Success)
{
    dynamic d = result.Data;
}

在上面的示例动态中,您不需要进行强制转换,但是同时您松开了对数据的强类型访问。 主要在进行互操作时建议使用。 如果您可以松开强类型访问权限,则可以使用它。 还有一件事,与此有关的任何错误都将在运行时执行。

您正在尝试创建类似于Option / Maybe monad的东西:)您可以考虑以下几种选择:

  1. 把所有东西放在“父母”里

     class Result<TValue> { TValue Value // throws if !HasValue bool HasValue string ErrorMessage // throws if HasValue } 

您可以使用适当的构造函数来处理派生类型Some,None(成功,失败),或者在父类型上使用静态“ create”方法+私有构造函数,或者使用扩展方法-无论您喜欢创建“ Success”,“ Failure”用。 返回此结果的函数将始终需要指定通用参数。

  1. 您所拥有的+“ pattern match” =“类型转换” =在呼叫方投放,即

     var result = GetClipboardFromDateTime(); switch(result) { case Success<ClipboardCopy[]>: ... break; case Failure: ... break; default: throw } 

(C#7功能),或者

    if (result is Success<ClipboardCopy[]>)
    (result as Success<ClipboardCopy[]>)?.Value 

等等

  1. 将成功/错误继续/回调放在Result类上

     Action<TValue> / Func<TValue, ?> onSuccess Action<string> / Func<string, ?> onError 

     result.OnSuccess(value => /* do smthn /w value */); result.OnError(errorMsg => /* do smthn /w error msg */); 

    (编辑)结果暗示:

     public void OnSuccess(Action<TValue> onSuccess) { if (!_hasValue) return; onSuccess(_value); } public void OnError(Action<string> onError) { if (_hasValue) return; onError(_errorMessage); } // alternatively public void Apply(Action<TValue> onSuccess, Action<string> onError) { if (_hasValue) { onSuccess(_value); return; } onError(_errorMessage); } 

    父结果将需要具有这些方法。 可以通过多种方式来完成(父impl可以是“不执行任何操作-成功与失败子项将覆盖而不检查_hasValue等)”。 OnSuccess(),OnError(),Apply()不必为空,您可以将Result<TResult> OnSuccess<TResult>(Func<TValue, TResult> onSuccess) (而不是void + Action<> )设为能够链接它们(我不会在C#中这样走:D)。

通常,在C#中,我会避​​免以这种方式从方法中“返回异常” /“错误代码”等-我相信您应该实现“快乐之路”并通过异常(如果可能)进行异常处理。 我真的很喜欢在TryGet()方法上使用这种“模式”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM