C#.Net中的可选返回

Hik*_*ari 44 .net c# nullable optional

Java 1.8正在接收Optional类,它允许我们明确说明方法何时可以返回空值并"强制"其使用者isPresent()在使用它之前验证它是否为null().

我看到C#有Nullable,它做了类似的事情,但有基本类型.它似乎用于数据库查询,以区分值何时存在,并且当它不存在时为0并且为空.

但似乎C#的Nullable不适用于对象,仅适用于基本类型,而Java的Optional仅适用于对象而不适用于基本类型.

在C#中是否有Nullable/Optional类,这迫使我们在提取和使用它之前测试对象是否存在?

Zor*_*vat 28

在我看来,任何Option暴露HasValue财产的实施都是整个想法的失败.可选对象的要点是,您可以无条件地调用其内容,而无需测试内容是否存在.

如果您必须测试可选对象是否包含值,那么与常见null测试相比,您没有做任何新的事情.

以下是我正在详细解释可选对象的文章:C#中的Option/Maybe Type的自定义实现

这里是带有代码和示例的GitHub存储库:https://github.com/zoran-horvat/option

如果您不愿意使用重量级的Option解决方案,那么您可以轻松构建轻量级的解决方案.您可以创建自己的Option<T>实现IEnumerable<T>接口的类型,以便您可以利用LINQ扩展方法将调用设置为可选.这是最简单的实现:

public class Option<T> : IEnumerable<T>
{
    private readonly T[] data;

    private Option(T[] data)
    {
        this.data = data;
    }

    public static Option<T> Create(T value)
    {
        return new Option<T>(new T[] { value });
    }

    public static Option<T> CreateEmpty()
    {
        return new Option<T>(new T[0]);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return ((IEnumerable<T>)this.data).GetEnumerator();
    }

    System.Collections.IEnumerator
        System.Collections.IEnumerable.GetEnumerator()
    {
        return this.data.GetEnumerator();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此Option<T>类型是通过LINQ完成的:

Option<Car> optional = Option<Car>.Create(myCar);
string color = optional
  .Select(car => car.Color.Name)
  .DefaultIfEmpty("<no car>")
  .Single();  // you can call First(), too
Run Code Online (Sandbox Code Playgroud)

您可以在这些文章中找到有关可选对象的更多信息

您可以参考我的视频课程,了解有关如何使用Option类型和其他方法简化控制流程的更多详细信息:在.NET中制作C#代码更多功能战术设计模式:控制流程

第一个视频课程(让您的C#代码更具功能性)详细介绍了面向铁路的编程,包括EitherOption类型以及它们如何用于管理可选对象和处理特殊情况和错误.

  • 我的观点是你永远不会测试`Optional`是否包含任何内容.只需调用该方法,让`Optional`将调用转发给包含的对象*如果*它包含任何东西.这就是你如何将一个if-else包含的可选调用转换为对可选对象的无条件调用. (6认同)
  • 谢谢。使用 Optional 的要点是,当某些软件错误允许在空指针上调用对象方法或字段时,它将抛出异常。当有人在使用指针之前忘记测试指针是否为空时,就会发生这种错误,并且编译器允许在没有测试的情况下编译调用。 (2认同)
  • @urig这个答案中的实现是基本的,除了构造Option之外,它还依赖于LINQ.在另一篇文章中,我实现了一个完整的Option类型,完全支持相关操作.该文章还包含与整个代码的GitHub repo链接.以下是文章:http://codinghelmet.com/?path =howto /custom-implementation-of-the-option-maybe-type-in​​-cs (2认同)

Ser*_*rvy 21

不是语言,不,但你可以自己做:

public struct Optional<T>
{
    public bool HasValue { get; private set; }
    private T value;
    public T Value
    {
        get
        {
            if (HasValue)
                return value;
            else
                throw new InvalidOperationException();
        }
    }

    public Optional(T value)
    {
        this.value = value;
        HasValue = true;
    }

    public static explicit operator T(Optional<T> optional)
    {
        return optional.Value;
    }
    public static implicit operator Optional<T>(T value)
    {
        return new Optional<T>(value);
    }

    public override bool Equals(object obj)
    {
        if (obj is Optional<T>)
            return this.Equals((Optional<T>)obj);
        else
            return false;
    }
    public bool Equals(Optional<T> other)
    {
        if (HasValue && other.HasValue)
            return object.Equals(value, other.value);
        else
            return HasValue == other.HasValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您将无法模拟某些行为Nullable<T>,例如能够将没有值的可空值设置为null,而不是盒装可空,因为它具有对该(以及其他一些)行为的特殊编译器支持.

  • @Kenneth OP没有要求避免空检查的方法; 他想方设法将可选值的概念包装成C#中的类型(对于类和结构).这样做. (16认同)
  • 这没有任何好处.您实现此目的的唯一方法是,如果开发人员不进行检查,则使用InvalidOperationException替换NullReferenceException.除此之外,你正在改变他检查null的方式.最后,它没有增加很多价值.如果您可以强制检查,这将是有用的,但这是不可能的. (11认同)
  • 据我所知,这也是Java中的情况.Java和C#等语言中的选项允许您表达从方法返回null的语义可能性.有些语言编译器会强制您检查但不是这两种语言.定义自己的类型的问题在于,只有您的代码才会使用它,并且您希望整个生态系统都使用它. (6认同)
  • @Kenneth嗯,一个优点是你可以统一结构和类之间的可空性概念.您可以将此系统用于*any*类型的对象,而不是为每种类型的对象使用不同的系统.现在,我会在我的程序中使用这样的东西,不,可能不是.我认为这不值得,但我不会说OP一定不能使用这样的课程. (3认同)
  • @Kenneth这种方法给你的另一件事是你可以对你的程序应用一些推理.如果你在任何地方都使用这种方法,那么你可以假设什么都不会为空(甚至使用AOP技术强制执行,参见[Fody.NullGuard](https://github.com/Fody/NullGuard))然后它变成当返回值或参数是一个可以为null的那个时显式,因为它将是Optional <T>,而不仅仅是一些你无法知道是否允许它为null的对象. (3认同)

Luk*_*och 13

在C#中有更好的选项类型实现.您可以通过pluralsight.com上的Zoran Horvat在.NET中的战术设计模式中找到这种实现方式.它包括解释为何以及如何使用它.基本思想是将选项类实现为IEnumerable <>接口的实现.

public class Option<T> : IEnumerable<T>
{
    private readonly T[] data;

    private Option(T[] data)
    {
        this.data = data;
    }

    public static Option<T> Create(T element)
    {
        return new Option<T>(new[] { element });
    }

    public static Option<T> CreateEmpty()
    {
        return new Option<T>(new T[0]);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return ((IEnumerable<T>) this.data).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的引用,+ 1. (8认同)
  • 他在这里写下了自己的答案。 (3认同)