You have a few options. None of them match exactly what you want, but depending on what kind of operations you need you might get close.
The first is to use a generic method where the generic type is restricted, but the only operations you can do are limited:
public void Update<T>(T[] arr, int startIndex, int endIndex) : IComarable
{
if (condition1)
{
//Do some array manipulation
}
else if (condition2)
{
//Do some array manipulation
}
else if (condition3)
{
if (subcondition1)
{
//Do some array manipulation
}
}
}
And the conditions and array manipulation in that function would be limited to expressions that use the following forms:
if (arr[Index].CompareTo(arr[OtherIndex])>0)
arr[Index] = arr[OtherIndex];
This is enough to do things like find the minimum, or maximum, or sort the items in the array. It can't do addition/subtraction/etc, so this couldn't, say, find the average. You can make up for this by creating your own overloaded delegates for any additional methods you need:
public void Update<T>(T[] arr, int startIndex, int endIndex, Func<T,T> Add) : IComarable
{
//...
arr[Index] = Add(arr[OtherIndex] + arr[ThirdIndex]);
}
You'd need another argument for each operation that you actually use, and I don't know how that will perform (that last part's gonna be a theme here: I haven't benchmarked any of this, but performance seems to be critical for this question).
Another option that came to mind is the dynamic
type:
public void Update(dynamic[] arr, int startIndex, int endIndex)
{
//...logic here
}
This should work, but for something called over and over like you claim I don't know what it would do to the performance.
You can combine this option with another answer (now deleted) to give back some type safety:
public void Update(float[] arr, int startIndex, int endIndex)
{
InternalUpdate(arr, startIndex, endIndex);
}
public void Update(double[] arr, int startIndex, int endIndex)
{
InternalUpdate(arr, startIndex, endIndex);
}
public void InternalUpdate(dynamic[] arr, int startIndex, int endIndex)
{
//...logic here
}
One other idea is to cast all the floats to doubles:
public void Update(float[] arr, int startIndex, int endIndex)
{
Update( Array.ConvertAll(arr, x => (double)x), startIndex, endIndex);
}
public void Update(double[] arr, int startIndex, int endIndex)
{
//...logic here
}
Again, this will re-allocate the array, and so if that causes a performance issue we'll have to look elsewhere.
If (and only if) all else fails, and a profiler shows that this is a critical performance section of your code, you can just overload the method and implement the logic twice. It's not ideal from a code maintenance standpoint, but if the performance concern is well-established and documented, it can be the worth the copy pasta headache. I included a sample comment to indicate how you might want to document this:
/******************
WARNING: Profiler tests conducted on 12/29/2014 showed that this is a critical
performance section of the code, and that separate double/float
implementations of this method produced a XX% speed increase.
If you need to change anything in here, be sure to change BOTH SETS,
and be sure to profile both before and after, to be sure you
don't introduce a new performance bottleneck. */
public void Update(float[] arr, int startIndex, int endIndex)
{
//...logic here
}
public void Update(double[] arr, int startIndex, int endIndex)
{
//...logic here
}
One final item to explore here, is that C# includes a generic ArraySegment<T>
type, that you may find useful for this.