Os exemplos de código a seguir fornecem contexto para minha pergunta.
A classe Room é inicializada com um delegado. Na primeira implementação da classe Room, não há guardas contra delegados que lançam exceções. Essas exceções aparecerão na propriedade North, onde o delegado é avaliado (nota: o método Main () demonstra como uma instância de Room é usada no código do cliente):
public sealed class Room
{
private readonly Func<Room> north;
public Room(Func<Room> north)
{
this.north = north;
}
public Room North
{
get
{
return this.north();
}
}
public static void Main(string[] args)
{
Func<Room> evilDelegate = () => { throw new Exception(); };
var kitchen = new Room(north: evilDelegate);
var room = kitchen.North; //<----this will throw
}
}
Sendo que prefiro falhar na criação do objeto do que ao ler a propriedade North, altero o construtor para private e apresento um método de fábrica estático chamado Create (). Este método captura a exceção lançada pelo delegado e lança uma exceção do wrapper, com uma mensagem de exceção significativa:
public sealed class Room
{
private readonly Func<Room> north;
private Room(Func<Room> north)
{
this.north = north;
}
public Room North
{
get
{
return this.north();
}
}
public static Room Create(Func<Room> north)
{
try
{
north?.Invoke();
}
catch (Exception e)
{
throw new Exception(
message: "Initialized with an evil delegate!", innerException: e);
}
return new Room(north);
}
public static void Main(string[] args)
{
Func<Room> evilDelegate = () => { throw new Exception(); };
var kitchen = Room.Create(north: evilDelegate); //<----this will throw
var room = kitchen.North;
}
}
O bloco try-catch torna impuro o método Create ()?
Create
também é impuro, porque chama.
Create
função não o protege de obter uma exceção ao obter a propriedade. Se o seu delegado jogar, na vida real, é muito provável que ele seja jogado apenas sob algumas condições. As chances são de que as condições de lançamento não estejam presentes durante a construção, mas estão presentes ao obter a propriedade.