Bit late to the party but a good solution which is also Linq to SQL compatible is:
List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };
List<string> inList1ButNotList2 = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inList2ButNotList1 = (from o in list2
join p in list1 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inBoth = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od != null
select od).ToList<string>();
Kudos to http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C