Pergunta

I have been stumbling over an annoyance of this form several times, so my question is: What is the best pattern/practice for code scenarios as below?

Here is an example of a method body I wrote recently:

public HashSet<char> SomeCharacters(IEnumerable<string> _hashes){

    HashSet<char> Result = new HashSet<char>();
    bool _firstpass = true;

    foreach (string _hash in _hashes) {
        if (_firstpass) {
            Result = new HashSet<char>(_hash);
            _firstpass = false;
        }
        else {
            // ...
            // some code that uses Result
        }
    }
    return Result;
}

This works fine, but what's annoying me is the first line

HashSet<char> Result = new HashSet<char>();

which I'd instinctively like to replace by HashSet<char> Result;. The compiler won't let me, because the else block uses Result which it does not recognize as instanciated, although I know it will be by the time the else block is executed.

The way above forces me to create Result twice, which is not good for many reasons (performance, code aesthetics, ...).

Please consider this question a question about scenarios like this, not only focussed on this particular example. Thanks!

Foi útil?

Solução 2

You could refactor to remove the flag:

public HashSet<char> SomeCharacters(IEnumerable<string> _hashes){

    string first = _hashes.FirstOrDefault();
    if(first == null) return new HashSet<char>();

    HashSet<char> Result = new HashSet<char>(first);

    foreach (string _hash in _hashes.Skip(1)) {
        // ...
        // some code that uses Result
    }
    return Result;
}

You will need to be sure that it is safe to enumerate _hashes more than once however.

Outras dicas

Just assign null to the variable initially:

HashSet<char> Result = null;

You can then also get rid of the _firstpass variable:

HashSet<char> Result = null;
foreach (string _hash in _hashes) {
    if (Result == null) {
        Result = new HashSet<char>(_hash);
    }
    else {
        // ...
        // some code that uses Result
    }
}

If the only purpose of iterating the collection of strings is to put all the characters of the strings in a HashSet<char> then you can do it simply like this:

var Result = new HashSet<char>(_hashes.SelectMany(s => s));

The principle here is that sometimes you can rewrite loops with "first pass create and add" logic into much simpler LINQ statements where you build the sequence and then create the final object using ToList or in this case the HashSet constructor.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top