Calculate divisors using prime factorization For learning purpouses I wrote a class that is supposed to find all divisors for a given integer. My class makes use of primes and prime factorization to speed things up a bit.
What can I improve in my class? 

Are there any microoptimiztations that could speed up the process? Any bad practices that should be avoided? I am by no means an expert at math, so feel free to be very nit-picky. :)

DivisorFinder Class

public class DivisorFinder
{
    /// &lt;summary&gt;
    /// The number that is searched for divisors
    /// &lt;/summary&gt;
    private int _number;

    /// &lt;summary&gt;
    /// Search new divisors for a given integer
    /// &lt;/summary&gt;
    /// &lt;param name="number"&gt;Integer that is searched for divisors&lt;/param&gt;
    public DivisorFinder(int number)
    {
        _number = number;
    }

    /// &lt;summary&gt;
    /// Find prime numbers up to a given maximum
    /// &lt;/summary&gt;
    /// &lt;param name="upperLimit"&gt;The upper limit&lt;/param&gt;
    /// &lt;returns&gt;All prime numbers between 2 and upperLimit&lt;/returns&gt;
    private IEnumerable&lt;int&gt; FindPrimes(int upperLimit)
    {
        var composite = new BitArray(upperLimit);
        var sqrt = (int) Math.Sqrt(upperLimit);

        for (int p = 2; p &lt; sqrt; ++p)
        {
            if (composite[p])
                continue;

            yield return p;

            for (int i = p * p; i &lt; upperLimit; i += p)
                composite[i] = true;
        }

        for (int p = sqrt; p &lt; upperLimit; ++p)
            if (!composite[p])
                yield return p;
    }

    /// &lt;summary&gt;
    /// Search prime factors in a given IEnumerable of prime numbers
    /// &lt;/summary&gt;
    /// &lt;param name="primesList"&gt;The IEnumerable of previously calculated prime numbers&lt;/param&gt;
    /// &lt;returns&gt;IEnumerable of prime factors&lt;/returns&gt;
    private IEnumerable&lt;(int, int)&gt; FindPrimeFactors(IEnumerable&lt;int&gt; primesList)
    {
        foreach (var prime in primesList)
        {
            if (prime * prime &gt; _number)
                break;
            int count = 0;
            while (_number % prime == 0)
            {
                _number = _number / prime;
                count++;
            }

            if (count &gt; 0)
                yield return ((prime, count));
        }

        if (_number &gt; 1)
            yield return (_number, 1);
    }

    /// &lt;summary&gt;
    /// Find all divisors of the target number
    /// &lt;/summary&gt;
    /// &lt;returns&gt;IEnumerable of integers that divide the target without reminder&lt;/returns&gt;
    public IEnumerable&lt;int&gt; FindDivisors()
    {
        var primes = FindPrimes((int) (Math.Sqrt(_number) + 1));
        var factors = FindPrimeFactors(primes);
        var divisors = new HashSet&lt;int&gt; {1};

        foreach (var factor in factors)
        {
            var set = new HashSet&lt;int&gt;();
            for (int i = 0; i &lt; factor.Item2 + 1; i++)
            {
                foreach (int x in divisors)
                {
                    set.Add((int) Math.Pow(x * factor.Item1, i));
                }
            }

            divisors.UnionWith(set);
        }

        return divisors;
    }
}


Usage

var number = 2147483644;
var divisorFinder = new DivisorFinder(number);
var divisors = divisorFinder.FindDivisors();
Console.WriteLine($"Divisors: [{string.Join(", ", divisors)}]");


Performance for this example: ~6 milliseconds on a i5-6600K @ 3.50GHz

Credits:

The class was inspired by the python example from Bruno Astrolino.

Furthermore the prime sieve function was adapted from Dennis_E.
Bugs

FindPrimes is one of the better sieve implementations I've seen posted on this site, but it has an out-by-one bug. Here's some test code, which you can tidy up in a unit testing framework if you want to do things properly:

    var df = new DivisorFinder(72);
    int[] knownPrimes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 };
    for (int limit = 1; limit &lt;= 50; limit++)
    {
        var expected = knownPrimes.Where(p =&gt; p &lt; limit);
        var observed = df.FindPrimes(limit);
        if (!expected.SequenceEqual(observed)) Console.WriteLine($"Error for limit {limit}");
    }




FindDivisors has a more alarming bug. What are the divisors of 72? According to this code, they include 144...



Structure

FindPrimes should be static: nothing in that method depends on instance fields or properties.

FindPrimeFactors modifies state, so it's not idempotent. Calling FindDivisors twice on the same object should give the same results, but it doesn't.

Frankly, this class is an example of OO purism at its worst. There's no good reason for any of the methods to be non-static.



IMO the dependency relationship between FindDivisors and FindPrimeFactors is wrong: FindPrimeFactors should be responsible for calculating which primes it needs to use. Consider that if you want to have multiple methods which use the prime factors in different ways, you shouldn't have to copy-paste the line

    var primes = FindPrimes((int) (Math.Sqrt(_number) + 1));


into every single one.