Есть два класса, наследника стандартных элементов управления winforms. Оба класса реализуют мой интерфейс IMyControl
public class MyUserControl : UserControl, IMyControl
{
public void Foo1 (int int1, int int2)
{
//реализация Foo1
}
public void Foo2 (string string1)
{
//реализация Foo2
}
}
public class MyPanel : Panel, IMyControl
{
public void Foo1 (int int1, int int2)
{
//реализация Foo1
}
public void Foo2 (string string1)
{
//реализация Foo2
}
}
public interface IMyControl
{
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
Теперь мне нужно реализовать класс-хэлпер следующего вида
public class MyControlHelper<T> where T : IMyControl
{
public void BuildTo(Control body, T child)
{
body.Controls.Add(child);
}
}
Хорошо, я знаю что мои классы реализующие IMyControl
можно добавить в дочерние к иному контролу. Но компилятор не знает. Хорошо, значит надо указать, что мой интерфейс включает IControl
и всего делов
public interface IMyControl : IControl
{
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
Ой. Но интерфейса IControl
в winforms почему-то нет. А какой же тип принимает в качестве параметра метод Control.Controls.Add
? Оказывается он принимает тип класса Control
.
Вот это уже как-то нехорошо... Может интерфейс в c# всё-таки может включать "интерфейс класса"?
public interface IMyControl : Control
{
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
Увы, нет (Что сложно было сделать?!)
Так как же мне реализовать MyControlHelper
?
Самый простой способ - поставить второе ограничение там, где это требуется:
public class MyControlHelper<T> where T : Control, IMyControl
{
public void BuildTo(Control body, T child)
{
body.Controls.Add(child);
}
}
В тех же местах, где такой вариант неприемлем - можно оставить только наиболее важное ограничение, а остальные сделать опциональными:
public void BuildTo(Control body, Control child)
{
body.Controls.Add(child);
}
public IEnumerable<IMyControl> GetMyControls(Control body)
{
// Нас интересуют только IMyControl, на остальные просто не обращаем внимания
return body.Controls.OfType<IMyControl>();
}
Более сложный вариант - инвертировать логику добавления: пусть контрол сам думает как правильно добавиться к родителю.
public interface IMyControl
{
void AttachTo(Control body);
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
public class MyControlHelper<T> where T : IMyControl
{
public void BuildTo(Control body, T child)
{
child.AttachTo(body);
}
}
Но тут надо помнить о том, что контрол вполне может сделать эту операцию как-то нестандартно, а потому надо хранить дополнительную коллекцию IMyControl
если в дальнейшем требуется добавленные таким образом контролы достать обратно:
public interface IMyControl
{
void AttachTo(Control body);
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
public class MyControlHelper<T> where T : IMyControl
{
static readonly ConditionalWeakTable<Control, List<T>>
childs = new ConditionalWeakTable<Control, List<T>>();
public void BuildTo(Control body, T child)
{
child.AttachTo(body);
childs.GetOrCreateValue(body).Add(child);
}
public IEnumerable<T> GetChilds(Control body)
=> childs.GetOrCreateValue(body);
}
Можно добавить в интерфейс метод AsControl()
public interface IMyControl
{
Control AsControl();
void Foo1 (int int1, int int2);
void Foo2 (string string1);
}
реализацию метода будет простая
public Control AsControl()
{
return this as Control;
}
код хэлпера, изменится лишь немного
public class MyControlHelper<T> where T : IMyControl
{
public void BuildTo(Control body, T child)
{
body.Controls.Add(child.AsControl());
}
}
UPD
Ну и в отличии от варианта от tym32167 здесь всё-таки вешается обязанность приводится к интерфейсу типа Control
, на классы реализующие IMyControl
, а не откладывается соответствие обязанности до вызова метода хэлпера.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Я так поняла, что если у меня данные IQueryable, то запрос выполняется, только когда я вызываю методы Count(), ToList() и подобные, либо начинаю перебирать...