Pull to refresh

Comments 19

так и не понял на кой такой изврат?
давайте еще поплачем про ковариантность — хотя в 4 некая имитация будет.
Ковариантность к данному конкретному вопросу отношения не имеет. Да и не плачем мы. Обсуждаем теоретическую полезность возможной фичи.
Так ли уж часто нужно возвращать объект того же самого типа из экземплярного метода? Ну т.е., кроме как Clone(), не могу придумать никакого общего применения этой штуке.
Ну вот хотя бы и Clone(). Разве одного метода мало? :)

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

Пример из нашего кода. С клиента приходят два объекта (десериализуется) — состояние до и после редактирования. Нужно сравнить их и сделать апдейт. Чтобы сравнить, делаем в дженерике метод bool Equals( TThis other ). Базовый метод сравнивает ощие для всех таких объектов свойства, а унаследованный добавляет к этому сравнение доп свойств.
Ну реализуйте в наследованном классе явный IComparable, а при необходимости обращайтесь к базовой реализации. Да, чуть больше кода, но зато без всяких хитростей.
Ну ведь я и не говорю, что проблема не решается стандартными средствами. Вообще-то, из c# можно выкинуть очень много всякого синтаксического сахара, и проблемы по-прежнему будут решаться. Но будет ли это так же приятно?
можно, например, вот так:
Copy Source | Copy HTML
  1. public TEntity Load(DataContext context, object pk)
  2.         {
  3.             var table = context.GetTable<TEntity>();
  4.             return table.Where(this.FilterByPk(pk)).SingleOrDefault();
  5.         }
  6.  
  7.  
  8. protected Expression<Func<TEntity, bool>> FilterByPk(object pk)
  9.         {
  10.             var entity = Expression.Parameter(typeof(TEntity), "ent");
  11.             var keyValue = Expression.Property(entity, primaryKey);
  12.             var primaryKeyValue = Expression.Constant(pk, keyValue.Type);
  13.             var body = Expression.Equal(keyValue, primaryKeyValue);
  14.             var expression = Expression.Lambda<Func<TEntity, bool>>(body, entity);
  15.             return expression;
  16.         }
  17. public void Do()
  18. {
  19. var doc = this.Load(dataContext, documentId);
  20.  
  21.             if (doc == null)
  22.             {
  23.                 doc = new TEntity()
  24.                           {
  25.                               CreationTime = DateTime.Now,
  26.                               id = documentId,
  27.                           };
  28.                 dataContext.GetTable<TEntity>().InsertOnSubmit(doc);
  29.             }
  30. }
  31.  
  32.  
Вот еще, узел дерева:

public class Node<T> 
{
  public List<Node<T>> Children;
  ...
}


А удобнее было бы для юзания:

public class Node<T>
{
  public List<TThis> Children;
  ...
}
У Мейера об этом тоже есть. У него много потрачено на объяснение полезности такой штуки. В Эйфель есть конструкции like anchor или like Current.

У него не только возврат значения. Например в классе есть несколько полей, по идее они должны быть во всех наследниках одного типа, заранее неизвестно какого, это определяется только в конкретной реализации наследника.
Конечно, не только возврат! Спасибо за наводку.
Прогресс на лицо, чувствую лет через пять можно будет переключаться с Nemerle на любой mainstream язык без такого уныния, которое испытываю сейчас=)
В первые топиком промахнулся, извините.
а я думал, чот я один такой извращенец)))
Copy Source | Copy HTML
  1. public partial class Budget : BaseDoc<Budget>
  2.     {}
  3. public abstract class BaseDoc<TEntity> : IDocument where TEntity : BaseDoc<TEntity>, new()
  4.     {}
Предлагаю в таких случаях вместо TEntity писать TThis.
Какая разница, что писать?

TThis — это вообще что-то невразумительное. Как вы себе представляете функцию, которая возвращает значение или принимает аргумент типа, которого еще не существует.

Вот так правильно:

Copy Source | Copy HTML
  1. public class Adapter<T>
  2. {
  3.   public virtual Adapter<T> DoSomething()
  4.   {
  5.      ...
  6.   }
  7.   public virtual U DoSomething<U>() where U: Adapter<T>, new()
  8.   {
  9.      ...
  10.   }
  11. }


Выбирайте первый или второй вариант, в зависимости от того, лень вам делать приведение типов или нет.
Это как раз неправильно. Я не хочу в DoSomething писать ничего. У Вас получается либо:

MyAdapter a = (MyAdapter)obj.DoSomething();

либо

MyAdapter a = obj.DoSomething();

Первй вариант просто неудобный, а второй и вовсе некорректный — тут вместо MyAdapter можно запихать и YourAdapter. Откомпилируется, но не заработает.

Вообще, вся эта система дженериков и служит для того, чтобы писать функции, которые оперируют еще не существующими типами. Мой пример сверху, с TThis вполне рабочий — он компилируется. Пример XuMiX корректен? Вполне. Я только считаю, что если вместо TEntity написать TThis, то будет понятнее.
Пардон, опечатка во втором варианте:
MyAdapter a = obj.DoSomething();
Мда, не опечатка. Угловые скобочки съелись. Подразумевалось вот такое:

MyAdapter a = obj.DoSomething<MyAdapter>(); 
Сдается мне что можно поменять одно неудобство на другое и написать extension method который будет выдавать тот тип что нужен. Что-нибудь вроде:
public static T DoSomething<T>(this T obj)
{
  ⋮
}
А может и нельзя ;) так или иначе, согласен – косячненько.
Sign up to leave a comment.

Articles