IDisposable and the using statement aren't inherently tied to either value or reference types, but the two interact in a way worth knowing:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
// ... use connection ...
} // Dispose() is called automatically here, even if an exception was thrown above
// Modern "using declaration" syntax — disposes at the end of the enclosing scope, not a nested block
using var reader = new StreamReader(path);
var content = reader.ReadToEnd();
A struct can implement IDisposable, and the .NET base class library has real examples (several enumerator structs, for instance) — the benefit is avoiding a heap allocation for a short-lived disposable object. But because a struct copies on every assignment or pass, it's easy to end up calling Dispose() on a copy while a different copy (still holding, say, an unmanaged handle) never gets cleaned up — a subtle enough problem that struct-based IDisposable types are considerably less common in application code than class-based ones, and are mostly reserved for very hot, allocation-sensitive paths written with the copying behavior explicitly in mind.