Reducing code duplication for my C# math class I have a library with a lot of duplicate code to accommodate different collection types, and its starting to get a bit tedious, is there a better way to do this to reduce the amount of duplication going on ? Its only going to get worse the more functions i add...

This is my current library script:

using System.Collections.Generic;
using UnityEngine;

namespace Math {
    public static class Geometry
    {
        public static float Area(List&lt;Vector2&gt; points)
        {
            float a = 0;
            for (int i = 0; i &lt; points.Count; i++)
            {
                var p1 = points[i];
                var p2 = points[(i + 1) % points.Count];

                a += p1.x * p2.y - p2.x * p1.y;
            }

            return a * 0.5f;
        }

        public static float Area(List&lt;Vector3&gt; points)
        {
            float a = 0;
            for (int i = 0; i &lt; points.Count; i++)
            {
                var p1 = points[i];
                var p2 = points[(i + 1) % points.Count];

                a += p1.x * p2.z - p2.x * p1.z;
            }
            return a * 0.5f;
        }

        public static float Area(Vector3[] points)
        {
            float a = 0;
            for (int i = 0; i &lt; points.Length; i++)
            {
                var p1 = points[i];
                var p2 = points[(i + 1) % points.Length];

                a += p1.x * p2.z - p2.x * p1.z;
            }
            return a * 0.5f;
        }

        public static float Area(Vector2[] points)
        {
            float a = 0;
            for (int i = 0; i &lt; points.Length; i++)
            {
                var p1 = points[i];
                var p2 = points[(i + 1) % points.Length];

                a += p1.x * p2.y - p2.x * p1.y;
            }
            return a * 0.5f;
        }

        public static bool IsClockwise(List&lt;Vector3&gt; points)
        {
            float sum = 0;

            for (int i = 0; i &lt; points.Count - 1; i++)
            {
                var point1 = points[i];
                var point2 = points[i + 1];

                sum += (point2.x - point1.x) * (point2.z + point1.z);
            }

            return sum &gt; 0;
        }
        public static bool IsClockwise(Vector3[] points)
        {
            float sum = 0;

            for (int i = 0; i &lt; points.Length - 1; i++)
            {
                var point1 = points[i];
                var point2 = points[i + 1];

                sum += (point2.x - point1.x) * (point2.z + point1.z);
            }

            return sum &gt; 0;
        }
        public static bool IsClockwise(List&lt;Vector2&gt; points)
        {
            float sum = 0;

            for (int i = 0; i &lt; points.Count - 1; i++)
            {
                var point1 = points[i];
                var point2 = points[i + 1];

                sum += (point2.x - point1.x) * (point2.y + point1.y);
            }
            return sum &gt; 0;
        }
        public static bool IsClockwise(Vector2[] points)
        {
            float sum = 0;

            for (int i = 0; i &lt; points.Length - 1; i++)
            {
                var point1 = points[i];
                var point2 = points[i + 1];

                sum += (point2.x - point1.x) * (point2.y + point1.y);
            }

            return sum &gt; 0;
        }
    }
}
Depending on how many points you'll be dealing with, you could go one step further.  Since you're only using 2 points from the Vector3, it's fairly simple to cast the Vector3's into Vector2's.

public static float Area(List&lt;Vector2&gt; points)
{
    float a = 0;
    for (int i = 0; i &lt; points.Count; i++)
    {
        var p1 = points[i];
        var p2 = points[(i + 1) % points.Count];

        a += p1.x * p2.y - p2.x * p1.y;
    }

    return a * 0.5f;
}

public static float Area(List&lt;Vector3&gt; points)
{

    return Area(points.Select(x =&gt; new Vector2(x.x,x.z)).ToList());
}

public static float Area(Vector3[] points)
{
    return Area(points.ToList());
}

public static float Area(Vector2[] points)
{
    return Area(points.ToList());
}


Upon further reflection the code reduction can be taken a step further by using IEnumerable&lt;T&gt;.  Now it becomes:

public static float Area(IEnumerable&lt;Vector2&gt; points)
{
    float a = 0;
    var first = points.First();
    var prev = first;
    foreach (var curr in points.Skip(1))
    {
        a += prev.x * curr.y - curr.x * prev.y;
        prev = curr;

    }
    a += prev.x * first.y - first.x * prev.y;
    return a * 0.5;
}

public static float Area(IEnumerable&lt;Vector3&gt; points)
{

    return Area(points.Select(x =&gt; new Vector2(x.x,x.z)));
}