Закрытия являются просто большими инструментами. Когда использовать их? Любое время Вам нравится... Как был уже сказан, альтернатива должна записать класс; например, пред C# 2.0, создавая параметризованный поток была реальная борьба. С C# 2.0 Вам даже не нужен 'ParameterizedThreadStart', который Вы просто делаете:
string name = // blah
int value = // blah
new Thread((ThreadStart)delegate { DoWork(name, value);}); // or inline if short
Сравнивают это с созданием класса с именем и оценивают
Или аналогично с поиском списка (использующий лямбду на этот раз):
Person person = list.Find(x=>x.Age > minAge && x.Region == region);
Снова - альтернатива должна была бы записать класс с двумя свойствами и методом:
internal sealed class PersonFinder
{
public PersonFinder(int minAge, string region)
{
this.minAge = minAge;
this.region = region;
}
private readonly int minAge;
private readonly string region;
public bool IsMatch(Person person)
{
return person.Age > minAge && person.Region == region;
}
}
...
Person person = list.Find(new PersonFinder(minAge,region).IsMatch);
Это справедливо сопоставимо с тем, как компилятор делает это под шляпой (на самом деле, это использует общедоступные поля чтения-записи, не частные только для чтения).
самый большой протест с получениями C# состоит в том, чтобы наблюдать объем; например:
for(int i = 0 ; i < 10 ; i++) {
ThreadPool.QueueUserWorkItem(delegate
{
Console.WriteLine(i);
});
}
Это не могло бы распечатать то, что Вы ожидаете, начиная с переменная я используюсь для каждого. Вы видели любую комбинацию повторений - даже 10 10-х. Необходимо тщательно определить объем полученных переменных в C#:
for(int i = 0 ; i < 10 ; i++) {
int j = i;
ThreadPool.QueueUserWorkItem(delegate
{
Console.WriteLine(j);
});
}
Здесь каждый j получен отдельно (т.е. различный сгенерированный компилятором экземпляр класса).
у Jon Skeet есть хорошая запись в блоге, касающаяся C# и закрытий Java здесь ; или для большего количества детали, см. его книгу C# подробно , который имеет всю главу по ним.
Как насчет создания GenericIdentity
и прикрепления его к Thread.CurrentPrincipal
в вашем тесте следующим образом:
[TestMethod]
public void TestMethod1()
{
var identity = new GenericIdentity("tester");
var roles = new[] { @"BUILTIN\Users" };
var principal = new GenericPrincipal(identity, roles);
Thread.CurrentPrincipal = principal;
var c = new MyClass();
}
Для проверки на сбой вы можете:
[TestMethod]
[ExpectedException(typeof(SecurityException))] // Or whatever it's called in MsTest
public void TestMethod1()
{
var identity = new GenericIdentity("tester");
var roles = new[] { @"BUILTIN\NotUsers" };
var principal = new GenericPrincipal(identity, roles);
Thread.CurrentPrincipal = principal;
var c = new MyClass();
}
Вы можете попробовать олицетворять разных пользователей в тестовом методе, если вы запустите код от имени администратора, вы можете создать локальную учетную запись пользователя внутри теста (или тестового класса) и удалите его в конце.
Edit: Извините, я представил, как использовать impersonate для проверки случая сбоя - я должен был правильно прочитать ваш вопрос :) У меня есть аналогичные модульные тесты, и они могут создавать локальные учетные записи в mstest. Другой вопрос, является ли это хорошей практикой.
Я вижу, вы уже сделали, как эта страница предлагает: установите для основной политики домена приложения значение «WindowsPrincipal». Для меня Thread.CurrentPrincipal.Identity.Name дает мое имя пользователя, и тест проходит с использованием VS 2005 и VS 2008, нацеленных на .NET 2.0, 3.0 и 3.5.
Вы используете Vista / Win7 с UAC и VS без повышенных прав? В противном случае сможете ли вы воспроизвести на другом компьютере, используя другую группу, или создав другую учетную запись локального администратора на своем компьютере и запустив тесты от имени этого пользователя?