public interface IBlackBox<T> {
bool IsValid();
T GetValue();
}
public abstract class Box<T>:IBlackBox<T> {
public bool IsValid() {
return true;
}
public abstract T GetValue();
}
Box
按需生成值;可能是按需计算,或随机,或只是花哨的可空等。BlackBox
做同样的事情,除了它可能会过期或以其他方式变得无效。 Box
需要适合BlackBox
列表(并且强调不是反向),这决定了继承层次结构。
我不喜欢的是Box
是抽象类而不是接口。这导致两个头痛。首先,这意味着我无法派生struct
,在Box
仅包含静态值的情况下,这将是非常优选的。
其次,这意味着我不能将其他任何子类化。例如,一个预期用途是Dictionary<string,BlackBox<int>>
,它本身就是Box
,并根据需要对其值进行求和。没有充分的理由这不应该仅仅是Dictionary
的子类,并且至少有一个非常好的理由:它不能逐行包装IDictionary
接口!但有些地方我需要Box
保证有效性,似乎我只能拥有一个或另一个。
我可能有一个interface IBox<T> : IBlackBox<T>
,它是空的,仅用作“信任我”标签。这意味着在每个实现Box
的类中重复IsValid()
的一行IBox<T>
,但这比手工包装IDictionary
要麻烦得多。不过,我希望有更具体的解决方案。
答案 0 :(得分:2)
这是我提出的最佳解决方案。这只是一块骨头,但我已经完成了一个完整的实现(更好的名字)on GitHub。
public interface IBlackBox
public interface IBlackBox<T> : IBlackBox {
Func<T> GetValue;
}
public interface IBox { }
public interface IBox<T> : IBlackBox<T>, IBox { }
public interface IWrappedBox { }
public interface IWrappedBox<T> : IBox<IBlackBox<T>>, IWrappedBox { }
public interface IEmptyBox { }
public static class EmptyBox {
public static EmptyBox<T> Get<T>() {
return EmptyBox<T>.value;
}
sealed class EmptyBox<T> : IBlackBox<T>, IEmptyBox {
public static readonly EmptyBox<T> value = new EmptyBox<T>();
public Func<T> GetValue {
get {
throw new NotSupportedException
("Cannot extract a value from an empty box.");
}
}
}
}
非通用接口允许在类型级别进行测试,例如:
IBlackBox something = someWrappedBox.GetValue();
if (something is IEmptyBox)
HandleEmpty();
else
HandleSomething(something.GetValue());
这仍然必须与编译器无法检查的三个规则相结合,但结构使其易于符合:
IBlackBox<T>
,IBlackBox
和IEmptyBox
无法直接继承。IWrappedBox<T>.GetValue()
才能返回基础IBlackBox<T>
。IEmptyBox
。 IEmptyBox
只有在明确允许时才会出现; IBox<T>
保证包含好T
;并且可以继承的所有东西都是一个接口。任务完成了!
答案 1 :(得分:0)
我建议使用一个IValidBox<T> : IBlackBox<T>
合同,该合同规定没有合法实施可能会IsValid
返回false,并且消费者有权致电GetValue
未检查IsValid
。另外,为了减少样板,你可以定义一个实现ValidBoxBase<T>
的抽象类IValidBox<T>
,这样不需要继承任何东西的IValidBox<T>
实现就可以节省一些样板。在这个简短的例子中并不多,但在更加充实的场景中可能会有很多。