Конкретная реализация универсального базового класса и метода расширения
Конечная цель этого поста - переопределить метод ToString() конкретной реализации универсального базового класса, сохраняя при этом возможность поиска реализации с использованием техники выравнивания Linq. Так что, если вы прочитаете это и увидите лучший способ, дайте мне знать. Я использую элементы управления Telerik для Silverlight, и они не изменят свои API, чтобы позволить некоторым из своих свойств элемента управления быть привязанными к данным, а вместо этого полагаются на метод ToString() любого объекта, с которым они связаны. да, глупо.. В любом случае вот что у меня есть.
Контроль RadTreeView на моей странице. Свойство FullPath каждого узла в древовидном представлении использует метод ToString() каждого элемента, с которым он связан (так что это то, что мне нужно переопределить).
Мне пришлось создать "промежуточный" класс, чтобы улучшить класс базовой модели, чтобы его можно было связать как иерархию в древовидном представлении, а затем конкретную реализацию этого универсального класса для переопределения ToString(). Теперь проблема в том, что у меня есть расширение Linq, которое взрывается, потому что оно не может преобразовать конкретную реализацию обратно в базовый универсальный класс. Я люблю дженерики, но это слишком много для меня. Нужна помощь в решении вопроса о методе расширения.
Посреднический родовой класс:
public class HeirarchicalItem<T> : NotifyPropertyChangedBase, INotifyCollectionChanged where T : class
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs ea)
{
if (CollectionChanged != null)
CollectionChanged(this, ea);
}
public HeirarchicalItem() { }
public HeirarchicalItem(T item)
{
Item = item;
}
public HeirarchicalItem(IEnumerable<T> collection)
{
CopyFrom(collection);
}
private T _item;
public T Item
{
get
{
return _item;
}
set
{
_item = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Item);
}
}
private ObservableCollection<HeirarchicalItem<T>> _children = new ObservableCollection<HeirarchicalItem<T>>();
public virtual ObservableCollection<HeirarchicalItem<T>> Children
{
get { return _children; }
set
{
_children = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private void CopyFrom(IEnumerable<T> collection)
{
if ((collection != null))
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
HeirarchicalItem<T> newHeirarchicalItem = new HeirarchicalItem<T>(enumerator.Current);
Children.Add(newHeirarchicalItem);
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
}
}
}
}
Класс базовой модели: (данные переносятся в службу WCF Ria и из нее с использованием этого класса)
public class tbl_Path : EntityBase, IFullPath, IEquatable<tbl_Path>, IEqualityComparer<tbl_Path>
{
public tbl_Path();
public int GetHashCode(tbl_Path obj);
public override string ToString();
public DateTime CreateDate { get; set; }
public short Depth { get; set; }
public string FullPath { get; set; }
public bool IsAuthorized { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
public override IEnumerable<Operation> Operations { get; }
public int? ParentPathID { get; set; }
public int PathID { get; set; }
public Guid SecurityKey { get; set; }
public EntityCollection<tbl_Configuration> tbl_Configuration { get; set; }
public EntityCollection<tbl_Key> tbl_Key { get; set; }
public EntityCollection<tbl_SecurityACL> tbl_SecurityACL { get; set; }
public EntityCollection<tbl_SecurityInheriting> tbl_SecurityInheriting { get; set; }
public EntityCollection<tbl_Variable> tbl_Variable { get; set; }
}
Конкретная реализация, так что я могу переопределить ToString():
public class HeirarchicalPath : HeirarchicalItem<tbl_Path>
{
public HeirarchicalPath()
{
}
public HeirarchicalPath(tbl_Path item)
: base(item)
{
}
public HeirarchicalPath(IEnumerable<tbl_Path> collection)
: base(collection)
{
}
public override string ToString()
{
return Item.Name; **// we override here so Telerik is happy**
}
}
И, наконец, вот метод расширения Linq, который взрывается во время компиляции, потому что я представил конкретную реализацию моего базового класса.
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
Фактический код, который ломается: (x.Children выделен с ошибкой)
Cannot implicitly convert type
'System.Collections.ObjectModel.ObservableCollection<HeirarchicalItem<tbl_Path>>' to
'System.Collections.Generic.IEnumerable<HeirarchicalPath>'. An explicit conversion
exists (are you missing a cast?)
HeirarchicalPath currentItem = this.Paths.Traverse(x => x.Children).Where(x => x.Item.FullPath == "$/MyFolder/Hello").FirstOrDefault();
1 ответ
Догадаться. Работая над этим весь день и минуты после публикации вопроса, я решаю его как всегда.
Просто нужно добавить этот бит в мою конкретную реализацию и больше никаких ошибок компилятора.
private ObservableCollection<HeirarchicalPath> _children = new ObservableCollection<HeirarchicalPath>();
public new ObservableCollection<HeirarchicalPath> Children
{
get
{
return _children;
}
set
{
if (value == null)
return;
_children = value;
RaisePropertyChanged<HeirarchicalPath>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}