Override ToString or provide an extension method not for ToString for an interface?

My question is about names, design and implementation options. I see that I am going in two different directions: how to solve the problem, and I’m interested in learning how to deal with the problem can other people who might encounter similar problems. It is part of aesthetics, part function.

A bit of background in the code ... I created a type called ISlice<T> , which provides a link to the source section of the elements, which can be a collection (for example, an array, list) or a string. The main support comes from several implementation classes that support fast indexing using Begin and End markers for slicing to get an element from the source. The goal is to provide slice capabilities similar to what Go provides when using Python style indexing (i.e., both positive and negative indexes are supported).

To create slices (instances of ISlice<T> ) easier and more fluently, I created a set of extension methods. For instance:

 static public ISlice<T> Slice<T>(this IList<T> source, int begin, int end) { return new ListSlice<T>(source, begin, end); } static public ISlice<char> Slice(this string source, int begin, int end) { return new StringSlice(source, begin, end); } 

There are others, such as providing optional start / end parameters, but the above will be enough for where I'm going with this.

These routines work well and make it easy to trim a collection or string. I also need a way to take a slice and create a copy of it as an array, list, or string. That things are becoming "interesting." Initially, I thought that I would need to create ToArray, ToList methods, but then I remembered that LINQ variants perform optimization if your collection implements ICollection<T> . In my case, ISlice<T> inherits from it, albeit very much to my chagrin, because I don't like to throw NotSupportedExceptions from methods like Add. Despite everything, I get them for free. Excellent.

How to convert back to string since there is no built-in support to convert IEnumerable<char> back to string? The closest thing I found is one of the lines. Concat overload, but it will not handle characters as efficiently as possible. Equally important from a design point of view is that it does not jump out of order as a β€œconversion procedure."

The first thought was to create a ToString extension method, but this does not work, because ToString is an instance method, which means that it intercepts extension methods and will never be called. I could override ToString, but the behavior would be inconsistent, since ListSlice<T> would have to use a special case for ToString for the time when T is char. I don't like this, because ToString will give something useful when the type parameter is char, but the class name in other cases. In addition, if other slicer types are created in the future, I will need to create a common base class to provide the same behavior, or each class will have to do the same test. The extension method on the interface will handle much more elegantly.

The extension method leads me to the question of naming. The use of ToString is obvious, but as mentioned earlier, this is not allowed. I could call it something else, but what? ToNewString? Newstring? CreateString? Something in the To-family method allowed it to enter the ToArray / ToList routines, but ToNewString appears as "odd" when viewed in the intellisense editor and in the code. NewString / CreateString is not as clear as you should know to look for them. It does not match the "conversion method" template that the To-family method provides.

Go with the ToString override and accept inconsistent behavior hardcoded into the ListSlice<T> implementation and other implementations? Come with a more flexible, but potentially more weakly named extension method route? Is there a third option that I have not considered?

My gut tells me to go with ToString, despite my reservations, however, it also happened to me ... Would you even think that ToString gives you useful output for type collection / enumerable? Does this violate the principle of least surprise?

Update

Most implementations of cutting operations provide a copy, albeit a subset, of the data from any source that was used for the slice. This is perfectly acceptable in most cases and goes beyond a pure API, as you can simply return the same data type back. If you cut the list, you return a list containing only the items in the range specified in the slice. If you slice a string, you return a string. And so on.

The cutting operations that I describe above solve the problem when working with constraints that make this behavior undesirable. For example, if you work with large data sets, slice operations will lead to unnecessary additional memory allocations, not to mention the impact of data copy performance. This is especially true if the slices process them until the final results are obtained. Thus, the goal of implementing a slice is to have references to larger data sets in order to avoid unnecessary copies of the information until it is beneficial for this.

The catch is that at the end of processing, there is a desire to turn processed data based on a slice into a more convenient type of API and .NET, such as lists, arrays and strings. This simplifies the transfer of data to other APIs. It also allows you to discard slices, thus also big data sets the slices that are referenced.

+4
source share
2 answers

Would you even think that ToString gives a useful result for type collection / enumerable? Does this violate the principle of least surprise?

No Yes. This would be completely unexpected behavior, as it will behave differently than any other type of collection.

Regarding this:

How about converting to a string since there is no built-in support for converting IEnumerable> char <easy to return to string?

Personally, I would just use a string constructor with an array :

 string result = new string(mySlice.ToArray()); 

This is explicit, understandable, and expected - I expect to create a new line by passing the object to the constructor.

+5
source

Perhaps the reason for your puzzle is the fact that you treat string as an ICollection<char> . You did not provide details about the problem you are trying to solve, but perhaps this is an incorrect assumption.

It is true that the string is an IEnumerable<char> . But, as you have noticed, assuming that direct matching with a collection of characters creates problems. Strings are just too "special" in the framework.

Looking at it from the other end, it would be obvious that the difference between ISlice<char> and ISlice<byte> is that you can associate the first with a string? Will there be some concatenate operation on the latter, which makes sense? What about ISlice<string> ? Shouldn't I be able to concatenate them?

Sorry, I do not give specific answers, but perhaps these questions will show you the correct solution to your problem.

+1
source

Source: https://habr.com/ru/post/1338024/


All Articles