Pergunta

No C # 3.0 e .NET 3.5, imaginar que há uma interface:

public interface INameable
{
  string Name {get;}
}

e muitas classes imutáveis ??que implementam a interface.

Eu gostaria de ter um único método de extensão

public static T Rename<T>(this T obj) where T : INameable
{ 
  ...
}

que retorna uma instância envolto do objeto original com apenas o nome alterado e todas as outras propriedades lê e chamadas de método encaminhado para o objeto original.

Como obter uma classe wrapper genérico para isso, sem implementá-lo para todos os tipos de aplicação INameable? Você acha que é possível?

Foi útil?

Solução

Não, isso não é possível, a menos que T é obrigado a ser uma interface ou para ser uma classe com todos os membros virtuais, e essa restrição não é possível especificar em tempo de compilação (embora você poderia escrever um cheque de tempo de execução se você está feliz com essa abordagem).

A razão que você não pode fazer isso para tipos arbitrários é que se você tomar um objeto do tipo T então você deve retornar um objeto que pode ser atribuído a T. Se eu passar um objeto que tem o seguinte aspecto ...

public sealed class SomeClass : INameable
{
    public string Name { get; }
    public string Abc { get; }
}

... então não há nenhuma maneira você pode criar outro tipo que é atribuído a SomeClass. Não usando Reflection.Emit ou qualquer outro método, porque o tipo é selado.

No entanto, se você está feliz com as restrições que mencionei, então você poderia usar algo como o quadro Castelo DynamicProxy para criar um tipo que proxies o passado no objeto e intercepta as chamadas para a frente ou para re-implementar como apropriada.

Outras dicas

Bem, sim, é possível, mas envolve a geração de código na memória.

Você pode olhar para Reflection.Emit e aqui .

Note que vai envolver um monte de código.

Isto é, se eu supor que eu entendi corretamente.

Aqui está o que eu acho que você está pedindo:

SomeNameableObject a1 = new SomeNameableObject("ThisIsTheFirstName");
SomeNameableObject a2 = a1.Rename("ThisIsTheSecondName");
// a1 works, still has the name ThisIsTheFirstName
// a2 works, but everything is routed to a1,
//    except for the name, which is ThisIsTheSecondName

Isso está correto?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top