I would do something like:
string[] names = new[] { "Foo", "Bar", "Fix" };
// The weights will be 3, 2, 1
int[] weights = new int[names.Length];
for (int i = 0; i < names.Length; i++)
{
    weights[i] = names.Length - i;
}
int[] cumulativeWeights = new int[names.Length];
// The cumulativeWeights will be 3, 5, 6
// so if we generate a number, 1-3 Foo, 4-5 Bar, 6 Fiz
cumulativeWeights[0] = weights[0];
int totalWeight = weights[0];
for (int i = 1; i < cumulativeWeights.Length; i++)
{
    cumulativeWeights[i] = cumulativeWeights[i - 1] + weights[i];
    totalWeight += weights[i];
}
var rnd = new Random();
while (true)
{
    int selectedWeight = rnd.Next(totalWeight) + 1; // random returns 0..5, +1 == 1..6
    int ix = Array.BinarySearch(cumulativeWeights, selectedWeight);
    // If value is not found and value is less than one or more 
    // elements in array, a negative number which is the bitwise 
    // complement of the index of the first element that is 
    // larger than value.
    if (ix < 0)
    {
        ix = ~ix;
    }
    Console.WriteLine(names[ix]);
}
I've built an array of weight. I have used a linear method. The first element has weight equal to (number of elements), the second one has weight (number of elements - 1) and so on. You can use your algorithm, but it is easier if the weight is integer.
Then I calculated a cumulativeWeights array and a totalWeight.
Then I can extract a binary number between 1 and totalWeight and find the index that has the cumulativeWeight that is <= the random number. Being cumulativeWeights sorted (clearly :-) ), I can use Array.BinarySearch, that has the advantage that if the exact number isn't found, the index to the next greatest number is given.
Now, with double weights it gets a little more complex for the Random part:
string[] names = new[] { "Foo", "Bar", "Fix" };
// The weights will be 3.375, 2.25, 1.5
double[] weights = new double[names.Length];
for (int i = 0; i < names.Length; i++)
{
    weights[i] = Math.Pow(1.5, names.Length - i);
}
double[] cumulativeWeights = new double[names.Length];
// The cumulativeWeights will be 3.375, 3.375+2.25=5.625, 3.375+2.25+1.5=7.125
// so if we generate a number, 1-3.375 Foo, >3.375-5.625 Bar, >5.625-7.125 Fiz
// totalWeight = 7.125
cumulativeWeights[0] = weights[0];
double totalWeight = weights[0];
for (int i = 1; i < cumulativeWeights.Length; i++)
{
    cumulativeWeights[i] = cumulativeWeights[i - 1] + weights[i];
    totalWeight += weights[i];
}
var rnd = new Random();
while (true)
{
    // random returns (0..1 * totalWeight - 1) + 1 = (0...6.125) + 1 = 1...7.125
    double selectedWeight = (rnd.NextDouble() * (totalWeight - 1)) + 1; 
    int ix = Array.BinarySearch(cumulativeWeights, selectedWeight);
    // If value is not found and value is less than one or more 
    // elements in array, a negative number which is the bitwise 
    // complement of the index of the first element that is 
    // larger than value.
    if (ix < 0)
    {
        ix = ~ix;
    }
    Console.WriteLine(names[ix]);
}
The Random.NextDouble() method returns a number 0<=x<1 that we have to convert to our weight.
Based on that principle, it is possible to build a List<T> class that uses it:
public class ListWithWeight<T>
{
    private readonly List<T> List = new List<T>();
    private readonly List<double> CumulativeWeights = new List<double>();
    private readonly Func<int, double> WeightForNthElement;
    private readonly Random Rnd = new Random();
    public ListWithWeight(Func<int, double> weightForNthElement)
    {
        WeightForNthElement = weightForNthElement;
    }
    public void Add(T element)
    {
        List.Add(element);
        double weight = WeightForNthElement(List.Count);
        if (CumulativeWeights.Count == 0)
        {
            CumulativeWeights.Add(weight);
        }
        else
        {
            CumulativeWeights.Add(CumulativeWeights[CumulativeWeights.Count - 1] + weight);
        }
    }
    public void Insert(int index, T element)
    {
        List.Insert(index, element);
        double weight = WeightForNthElement(List.Count);
        if (CumulativeWeights.Count == 0)
        {
            CumulativeWeights.Add(weight);
        }
        else
        {
            CumulativeWeights.Add(CumulativeWeights[CumulativeWeights.Count - 1] + weight);
        }
    }
    public void RemoveAt(int index)
    {
        List.RemoveAt(index);
        CumulativeWeights.RemoveAt(List.Count);
    }
    public T this[int index]
    {
        get
        {
            return List[index];
        }
        set
        {
            List[index] = value;
        }
    }
    public int Count
    {
        get
        {
            return List.Count;
        }
    }
    public int RandomWeightedIndex()
    {
        if (List.Count < 2)
        {
            return List.Count - 1;
        }
        double totalWeight = CumulativeWeights[CumulativeWeights.Count - 1];
        double selectedWeight = (Rnd.NextDouble() * (totalWeight - 1.0)) + 1;
        int ix = CumulativeWeights.BinarySearch(selectedWeight);
        // If value is not found and value is less than one or more 
        // elements in array, a negative number which is the bitwise 
        // complement of the index of the first element that is 
        // larger than value.
        if (ix < 0)
        {
            ix = ~ix;
        }
        // We want to use "reversed" weight, where first items
        // weight more:
        ix = List.Count - ix - 1;
        return ix;
    }
}
and
var lst = new ListWithWeight<string>(x => Math.Pow(1.5, x));
lst.Add("Foo");
lst.Add("Bar");
lst.Add("Fix");
lst.RemoveAt(0);
lst.Insert(0, "Foo2");
while (true)
{
    Console.WriteLine(lst[lst.RandomWeightedIndex()]);
}