C# 将方法强制转换为泛型和非泛型类
我想具体点。我有一个名为Result的类,还有一个派生类,名为ResultC# 将方法强制转换为泛型和非泛型类,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成
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);
}