The title basically spells it out. What interfaces have you written that makes you proud and you use a lot. I guess the guys that wrote IEnumerable<T>
and not least IQueryable<T>
had a good feeling after creating those.
views:
531answers:
6I guess the guys that wrote IEnumerable … had a good feeling after creating [it].
I'm not so sure. IEnumerable
was quite a failure, as interfaces go. This is evident from the fact that IEnumerable<T>
, its generic counterpart, actually offers a completely different interface. (Well, “different” isn't a good word; basically, it adds disposability and de-emphasizes the completely useless Reset
method; however, this method is of course still present.)
Additionally, similar languages that have similar constructs (Java comes to mind) have a much better, more extensible construct to fulfill the same needs (and more). For example, Java's iterators can be extended to be bidirectional or to allow modifying access (whereas IEnumerable
is always read-only).
EDIT: Since there's so much controversy in the comments, let me clarify. I'm not saying that IEnumerable
(or IEnumerator
) are bad interfaces. They're adequate. However, they could have been made better. If nothing else, then at least the Reset
method seems like clutter.
Terjet said that he “use[s] it all the time” – which is precisely my point! IEnumerable
is a pivotal interface of the whole .NET framework. It's ubiquitous. There'd be no .NET without it. Is it therefore too much to ask for a perfect interface?
“Adequate” is just another word for failure.
I'm pleased with the design of the interface at the heart of Push LINQ. It's a very simple interface, but with it you can do all kinds of interesting things. Here's the definition (from memory, but it'll be pretty close at least):
public interface IDataProducer<T>
{
event Action<T> DataProduced;
event Action EndOfData;
}
Basically it allows observers to "listen" on a stream of data instead of "pulling" from it in the way that IEnumerable works.
Three points of interest:
- The name sucks. I want to rename it, and I've had some good feedback, but the name isn't there yet.
- The event handlers don't follow the standard .NET conventions of having a sender/event args. In this case it really doesn't make much sense to do so.
- The multicast nature of events makes this perfect for calculating multiple aggregates etc. All that comes for free.
Strictly an interface? Or just an API? I'm kinda pleased with how the generic operator stuff worked out (available here) - I regularly see people asking about using operators with generics, so I'm glad it is a handy answer for a lot of people. It might be slightly easier in C# 4.0, but I very much doubt it will be as fast - the DLR-tree/dynamic stuff has an overhead.
I'm also quite happy that it was helpful in the Push LINQ that Jon has already mentioned ;-p
I am working on a validation system I plan on releasing to the community soon. It is essentially an implementation of the Specification pattern.
The core interface is designed to be functional in nature:
public interface ICheckable<T>
{
CheckResult Apply(T target);
}
CheckResult
is a struct
representing a tri-state value: Passed
, Failed
, and Ignored
. All of the conversion and operator overloads are in place to treat it as a Boolean
value.
This allows validators to express "I have no opinion" instead of returning a misleading true
value (think RangeValidator
indicating an empty field is valid so it plays nice with RequiredFieldValidator
).
Composition comes naturally and is done with static classes a la Linq. Each dot into the check is an implicit And
of the next operation:
public static ICheckable<T> Add<T>(this ICheckable<T> check, ICheckable<T> otherCheck)
{
return new Check<T>(t => check.Apply(t) && otherCheck.Apply(t));
}
public static ICheckable<T> Either<T>(this ICheckable<T> check, ICheckable<T> firstCheck, ICheckable<T> secondCheck)
{
return check.Add(t => firstCheck.Apply(t) || secondCheck.Apply(t));
}
public static ICheckable<T> Not<T>(this ICheckable<T> check, ICheckable<T> negatedCheck)
{
return check.Add(t => !negatedCheck.Apply(t));
}
Extension methods work nicely:
public static ICheckable<int> Percentage(this ICheckable<int> check)
{
return check.Add(n => n >= 0 && n <= 100);
}
public static ICheckable<T> GreaterThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
return check.Add(t => t.CompareTo(value) >= 0);
}
public static ICheckable<T> LessThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
return check.Add(t => t.CompareTo(value) <= 0);
}
public static ICheckable<T> Range<T>(this ICheckable<T> check, T minimum, T maximum) where T : IComparable<T>
{
return check.GreaterThanOrEqualTo(minimum).LessThanOrEqualTo(maximum);
}
// RangeExcludeMinimum
// RangeExcludeMaximum
// RangeExclusive
Each operation includes overloads which take a check-building lambda:
public static ICheckable<T> Add<T>(this ICheckable<T> check, Func<ICheckable<T>, ICheckable<T>> makeCheck)
{
return check.Add(makeCheck(new IgnoredCheck<T>()));
}
So you can do syntax like this:
ICheckable<int> check;
check.Add(i => i.Percentage().GreaterThan(50).Even());
This is an ActionScript 3 interface which was the core of our for the Flash Player's new behaviour in as3.
public interface IDisposable {
public function dispose():void;
}
As you'd expect, the dispose
method should close any resources and drop any references to anything it possibly can.
C++ programmers may scoff at this 'innovative' interface (which is totally fair enough), but as3 introduced a whole lot of issues surrounding memory management in Flash. These issues are all "old hat" for many compiled languages, but actionscript programmers are just now experiencing these challenges for the first time.
Yes, it's still a garbage collected language. But for better or worse, there's a lot less 'hand-holding' than in ActionScript 2, as evidenced by the need for this interface.
For doing MVP-pattern work I have a few basic framework interfaces:
public interface IValidatable {
bool IsValid { get; set; }
void ShowValidationFailureMessage(string message);
}
public interface ISubmitable {
event EventHandler Submit;
void ShowSubmitFailureMessage(string message);
void ShowSubmitSuccessMessage(string message);
}
public interface ICancelable {
event EventHandler Cancel;
}
With these 3 interfaces I can write presenter which has these generic operations (which cover basically all form operations). Eg:
public interface ILogin : IValidatable, ISubmitable, ICancelable {
string Username { get; set; }
string Password { get; set; }
}
You can then create a presenter and stub it out.