If you are really just trying to insert 30000 ID values that increment by 1, starting at 1002000, I highly doubt you'll be able to rig up anything in C# that will be faster than something like this:
INSERT ##MyTable(ID)
SELECT 1001999 + n FROM
(
SELECT TOP (30000) n = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
) AS x;
In my lowly Windows VM on a Mac host this occurs sub-second.
For other ideas about generating sets / sequences without looping (e.g. a numbers table may be even faster), see this blog series:
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-2
http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-3
If the values are defined and not some incremental sequence (e.g. 30,000 values you somehow coerced into a DataTable), then you can consider using a table-valued parameter. First, create this type in your database (you just do this once):
CREATE TYPE dbo.MyIDs AS TABLE(ID INT PRIMARY KEY);
Now have a stored procedure that accepts this:
CREATE PROCEDURE dbo.TakeMyIDs
@m dbo.MyIDs READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT ##MyTable(ID) SELECT ID FROM @m;
END
GO
Now call your stored procedure from C# and pass the DataTable as a parameter:
// assuming an active connection object, conn,
// and a populated DataTable called dtIDs:
SqlCommand cmd = new SqlCommand("dbo.TakeMyIDs", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvp1 = cmd.Parameters.AddWithValue("@m", dtIDs);
tvp1.SqlDbType = SqlDbType.Structured;
cmd.ExecuteNonQuery();
cmd.Dispose();