I just wrote my first C # class, so I'm looking for some comments before writing more code. The objective of the code is to provide a class similar to Singleton to deal with common operations in the set of prime numbers that I will need to complete projecteuler.net's problems.

I am interested in the feedback for all aspects of the implementation (except for the actual main generation algorithms, the `6 * i +/- 1`

The method was used solely for its simplicity).

I am also interested in comments on how the interfaces are divided. I divided them into parts of functionality in an attempt to allow future changes in the implementation. I'm planning to use DI (for example, SimpleInjector) to link the singleton instance to each of the interfaces, but I'm starting to doubt this pattern.

I am less interested in the comments on the method selections, I simply chose a relatively minimal subset of methods that I know I will need at some point; more methods will probably be added as necessary.

### Interfaces

```
public interface IPrimeGenerator
{
Enumerable PrimesUntilValue (long value);
Enumerable PrimesUntilCount (int account);
}
public interface IPrimeGenerator
{
Enumerable PrimesUntilValue (long value);
Enumerable PrimesUntilCount (int account);
}
public interface IPrimeFactorizer
{
Enumerable PrimeFactors (long value);
Enumerable UniquePrimeFactors (long value);
}
```

### Implementation

```
public class PrimeEngine: IPrimeGenerator, IPrimeChecker, IPrimeFactorizer
{
private readollly ICollection _primeCollection;
long private _indexFactor;
Private long _maxChecked;
PrimeEngine public ()
{
_primeCollection = new collection {2. 3};
_indexFactor = 1;
_maxChecked = 3;
}
Private vacuum CheckNextPossiblePrimeDoublet ()
{
var low = 6 * _indexFactor - 1;
var high = low + 2;
if (IsPrime (low))
{
_primeCollection.Add (low);
}
if (IsPrime (high))
{
_primeCollection.Add (high);
}
_indexFactor + = 1;
_maxChecked = high;
}
IEnumerable private GetPossibleSmallerPrimeFactors (long value)
{
FillPrimesUntilRoot (value);
return PrimesUntilRoot (value);
}
public bool IsPrime (long value)
{
var primePool = GetPossibleSmallerPrimeFactors (value);
returns primePool.All (prime => value% prime! = 0);
}
Private void FillPrimesUntilValue (long value)
{
while (_maxChecked <value)
{
CheckNextPossiblePrimeDoublet ();
}
}
private void FillPrimesUntilCount (int account)
{
while (_primeCollection.Count <count)
{
CheckNextPossiblePrimeDoublet ();
}
}
static long FloorOfRoot (long value)
{
return (long) Math.Floor (Math.Sqrt (value));
}
Private vacuum FillPrimesUntilRoot (long value)
{
FillPrimesUntilValue (FloorOfRoot (value));
}
IEnumerable public PrimesUntilValue (long value)
{
FillPrimesUntilValue (value);
returns _primeCollection.TakeWhile (prime => prime <= value);
}
IEnumerable public PrimesUntilCount (int account)
{
FillPrimesUntilCount (count);
return _primeCollection.Take (count);
}
IEnumerable public PrimesUntilRoot (long value)
{
return PrimesUntilValue (FloorOfRoot (value));
}
IEnumerable public PrimeFactors (long value)
{
FillPrimesUntilRoot (value);
foreach (var prime in PrimesUntilRoot (value))
{
if (prime> value) break;
while (value% prime == 0)
{
performance performance prime
value / = cousin;
}
}
yes (value! = 1)
{
yield return value;
}
}
IEnumerable public UniquePrimeFactors (long value)
{
returns PrimeFactors (value) .Distinct ();
}
}
```