Вопрос

Представьте, что в C# 3.0 и .NET 3.5 есть интерфейс:

public interface INameable
{
  string Name {get;}
}

и множество неизменяемых классов, реализующих интерфейс.

Я хотел бы иметь один метод расширения

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

который возвращает завернутый экземпляр исходного объекта с измененным только именем, а все остальные операции чтения свойств и вызовы методов перенаправляются на исходный объект.

Как получить для этого универсальный класс-оболочку, не реализуя его для всех типов реализации INameable?Как вы думаете, это возможно?

Это было полезно?

Решение

Нет, это невозможно, если только T ограничено интерфейсом или классом со всеми виртуальными членами, и это ограничение невозможно указать во время компиляции (хотя вы можете написать проверку во время выполнения, если вас устраивает такой подход).

Причина, по которой вы не можете сделать это для произвольных типов, заключается в том, что если вы возьмете объект типа T то вы должны вернуть объект, который можно назначить T.Если я передам объект, который выглядит следующим образом...

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

...тогда вы не сможете создать другой тип, который можно будет назначить SomeClass.Не используется Reflection.Emit или любой другой метод, потому что тип запечатан.

Однако, если вас устраивают упомянутые мной ограничения, вы можете использовать что-то вроде платформы Castle DynamicProxy для создания типа, который проксирует переданный объект и перехватывает вызовы для пересылки или повторной реализации в зависимости от ситуации.

Другие советы

Ну да, это возможно, но это предполагает генерацию кода в памяти.

Вы можете посмотреть Отражение.Emit и здесь.

Обратите внимание, что это потребует большого количества кода.

То есть, если я предполагаю, что правильно вас понимаю.

Вот что, я думаю, вы просите:

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

Это верно?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top