我不知道是否有实现在C#泛型空对象模式的任何做法。 通用null对象是所有的引用类型的子类,就像Nothing
在斯卡拉。 这好像是
public class Nothing<T> : T where T : class
但它不能编译,我不知道如何实现的方法T
提供默认的行为或抛出异常 。 下面是一些思路:
- 使用反射?
- 在创建时使用表达式树
Nothing<T>
它也许看起来像起订量。 而另一个问题来了:那是正确的产品代码使用模拟框架/库? - 使用动态类型?
我知道,也许我应该实现对特定类型的特定空对象。 我只是好奇,想知道是否有任何解决方案。
任何建议? 谢谢。
有了泛型,你不能从定义继承T
。 如果您的目的是使用if(x is Nothing<Foo>)
那么,仅仅是行不通的。 并非最不重要的,你需要考虑抽象类型,密封型和非默认构造。 但是,你可以这样做:
public class Nothing<T> where T : class, new()
{
public static readonly T Instance = new T();
}
然而,IMO失败大部分的空对象的主要特征; 特别是,你可以很容易地结束与某人做的:
Nothing<Foo>.Instance.SomeProp = "abc";
(也许意外,传递对象3级的水平向下之后)
坦率地说,我觉得你应该只检查null
。
这个怎么样?
public class Nothing<T> where T : class
{
public static implicit operator T(Nothing<T> nothing)
{
// your logic here
}
}
由于是密封类,您不能在普通的情况下,这样的继承。 预计不会很多类从派生,所以它可能不是好主意,如果这是可行的。
使用由@abatishchev建议隐含操作听起来像一个可能的方法。
我用在我的项目是这样的:
public interface IOptional<T> : IEnumerable<T> { }
public interface IMandatory<T> : IEnumerable<T> { }
自IEnumerable衍生与LINQ兼容性两个接口
public class Some<T> : IOptional<T>
{
private readonly IEnumerable<T> _element;
public Some(T element)
: this(new T[1] { element })
{
}
public Some()
: this(new T[0])
{}
private Some(T[] element)
{
_element = element;
}
public IEnumerator<T> GetEnumerator()
{
return _element.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Just<T> : IMandatory<T>
{
private readonly T _element;
public Just(T element)
{
_element = element;
}
public IEnumerator<T> GetEnumerator()
{
yield return _element;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
类的实现只是和一些
注意:这个班的实施是非常相似的,但它有一个性差异。 类从接口IMandatory刚刚得到的,只有一个构造函数,它保证类的该实例就总是有内部的值。
public static class LinqExtensions
{
public static IMandatory<TOutput> Match<TInput, TOutput>(
this IEnumerable<TInput> maybe,
Func<TInput, TOutput> some, Func<TOutput> nothing)
{
if (maybe.Any())
{
return new Just<TOutput>(
some(
maybe.First()
)
);
}
else
{
return new Just<TOutput>(
nothing()
);
}
}
public static T Fold<T>(this IMandatory<T> maybe)
{
return maybe.First();
}
}
一些扩展实用性
注意:扩展方法匹配需要两个函数,返回IMandatory,在此之后,扩展方法折使用。首先()没有任何检查。
现在我们可以使用LINQ的全功率和编写代码类似这一个(我的意思是单子.SelectMany())
var five = new Just<int>(5);
var @null = new Some<int>();
Console.WriteLine(
five
.SelectMany(f => @null.Select(n => f * n))
.Match(
some: r => $"Result: {r}",
nothing: () => "Ups"
)
.Fold()
);
如何在.NET Framework中已经存在的执行可空吗? http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx