C# 将方法强制转换为泛型和非泛型类

C# 将方法强制转换为泛型和非泛型类,c#,generics,C#,Generics,我想具体点。我有一个名为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; } } 公共类结果 { 公共字符串消息{get;set;} 公共bool成

我想具体点。我有一个名为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; }
}
公共类结果
{
公共字符串消息{get;set;}
公共bool成功{get;set;}
}
公开课成绩:成绩
{
公共T数据{get;set;}
}
这些类在方法中用作返回类型。为此,我创建了以下帮助器类:

公共类ResultManager
{
/// 
///返回一个成功的操作
/// 
公共静态结果成功()
{
var result=新结果{Success=true};
返回结果;
}
/// 
///返回一个成功的操作
/// 
///要随结果返回的对象类型
公共静态结果成功(T数据)
{
var result=新结果{Success=true,Data=Data};
返回结果;
}
/// 
///返回失败的结果
/// 
公共静态结果失败(字符串errorMessage=null,异常=null)
{
//…与问题无关的代码
返回新结果{Success=false,Message=errorMessage};
}
}
如您所见,上面的代码有两种成功的返回类型,一种是如果您不想返回任何内容,另一种是如果您想返回某些内容,但失败的结果永远不会返回任何内容。这是不必要的,只是一条错误消息。 这就引出了以下问题:当我想创建一个方法,该方法可以使用返回类型返回成功,而没有返回类型返回失败时,我如何转换它来确定返回类型是成功(通用)还是失败? 就像这里的方法:

//方法的返回类型是Result,因为Result是从它派生的
公共静态结果GetClipboardFromDateTime(DateTime DateTime)
{
//搜索项目
IEnumerable items=null;
尝试
{
items=mClipboardCollection.Where(a=>a.CopiedTime==dateTime);
}
捕获(例外情况除外)
{
//这将返回类“Result”
返回ResultManager。失败(
“从剪贴板中获取副本时出错。”,例如);
}
//如果没有值

如果(items.Count()尝试预先转换时出现问题。方法返回两种类型的结果

  • 成功
  • 失败
  • 我想你应该这样做

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

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

    您正在尝试创建类似于Optio的内容不,也许是单子:) 您可以考虑的选项很少:

  • 把所有东西都放在“家长”里

    (编辑)结果impl:

    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);
    }
    
    public void OnSuccess(Action OnSuccess){
    如果(!\u hasValue)返回;
    onSuccess(_值);
    }
    公共无效申报人(诉讼申报人){
    如果(_hasValue)返回;
    onError(_errorMessage);
    }
    //或者
    公共无效申请(成功时的行动、错误时的行动){
    如果(_hasValue){
    onSuccess(_值);
    返回;
    }
    onError(_errorMessage);
    }
    
    父结果将需要有这些方法。可以通过多种方式完成,(父impl可以是“不做任何事情”-成功和失败的子级将覆盖而不检查\u hasValue等)。OnSuccess()、OnError()、Apply()不必为空,您可以使用
    结果OnSuccess(Func OnSuccess)
    (而不是
    void
    +
    Action
    )来链接它们(虽然在C#D中我不会这样做)


  • 一般来说,在C#中,我会避免以这种方式从方法中“返回异常”/“错误代码”等-我认为您应该实现“快乐路径”,并通过异常(如果可能)完成异常处理。我非常喜欢在TryGet()上使用这种“模式”方法。

    当它崩溃时,错误消息是什么?System.InvalidCastException:“无法将对象从类型”AdvancedClipboard.Desktop.Models.Result“转换为类型”AdvancedClipboard.Desktop.Models.Result“1[AdvancedClipboard.Desktop.Models.ClipboardCopy[]]“.“基类<代码>结果”的意义是什么?正如你自己所看到的,处理它的第一件事是将它转换为其他东西。当基类的实例转换为派生类的实例时,当它实际上不是派生类时,你会期望什么?C#设计者决定抛出一个异常(你已经向我们展示了这个异常),认为这是程序员的错误。@ZdeněkJelínek是的,但第二个结果:“没有使用该日期时间的副本。”不是编程错误。为什么不总是返回一个
    结果
    ?在某些情况下,您可能没有任何数据,但这不会给您带来问题……您能解释一下为什么“动态”吗不建议使用?除非您删除if语句,否则第二个选项实际上是无用的。如果不检查是否删除,那么它将在运行时失败,因为当失败的结果返回时,它没有数据。在这种情况下,我会说不要使用动态,因为您应该知道结果的类型,所以强制转换将更可取。这就是为什么我给出o一个可能的解决方案,但写了我不建议。这是一个非常好的答案。另外,你能解释我的延续/回调吗?我试图做到,但我不能。也许一个链接?编辑了我的答案。你可能有兴趣搜索“C#也许单子”,“C#选项单子”,看看每个好帖子都有什么可能。我不理解w为什么它的票数与我的相距如此之远?我刚刚发现了一个讨论类似话题的问题(提出了一个问题,为什么不直接使用FP语言:D)
    class Result<TValue>
    {
      TValue Value // throws if !HasValue
      bool HasValue 
      string ErrorMessage // throws if HasValue
    }
    
    var result = GetClipboardFromDateTime();
    switch(result)
    {
      case Success<ClipboardCopy[]>: ... break;
      case Failure: ... break;
      default: throw
    }
    
        if (result is Success<ClipboardCopy[]>)
        (result as Success<ClipboardCopy[]>)?.Value 
    
    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);
    }