Здравствуйте DarkGray, Вы писали:
U>>Убедительно Полностью согласен Но опять же это просто облегчение. Та же проблема в COM.
DG>Если Com реализовался на языке C++, то проблем не было.
Были еще какие.
IInterface1 и его реализация — в одной Dll, написанной на С++.
IInterface2 и его реализация — в другой DLL, написанной на С++.
Как наследование реализации строить для IInterace3, который должен наследоваться от обоих?
U>Были еще какие. U>IInterface1 и его реализация — в одной Dll, написанной на С++. U>IInterface2 и его реализация — в другой DLL, написанной на С++. U>Как наследование реализации строить для IInterace3, который должен наследоваться от обоих?
Если именно наследоваться, то никак...
А если без наследования, то можно было через агрегацию подцепить.
Здравствуйте DarkGray, Вы писали:
DG>А если без наследования, то можно было через агрегацию подцепить.
Убедил, Множественое наследование помогло бы в некоторых ситуациях Правда могло и внести изрядно путаницы. А в случае множетства наследуемых интерфейсов... в конце концов можно с скопировать реализацию Если исходныйкод доступен Но прописывать похожие свойства действительно бесит.
Здравствуйте DarkGray, Вы писали:
DG>И как эту задачу решить без множественного наследования?
Меня удивляет, что нигде в современных языках не встречается такая конструкция (ведь наследование реализации можно представить комбинацией аггрегации и делегирования) —
public interface IActive
{
public bool IsActive
{
get;
set;
}
}
public class ActiveImpl : IActive
{
bool _isActive;
public bool IsActive
{
get {return _isActive;}
set {_isActive = value;}
}
}
public interface INaming
{
public string Name
{
get;
set;
}
}
public class NamingImpl : INaming
{
string _name;
public string Name
{
get {return _name;}
set {_name = value;}
}
}
public class GenericClass : IActive, INaming
{
// all IActive calls are delegated to this objectprivate implements IActive active = new ActiveImpl();
// all INaming calls are delegated to this instanceprivate implements INaming naming = new ActiveImpl();
}
вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
A>Меня удивляет, что нигде в современных языках не встречается такая конструкция A>вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
Нечто очень близкое есть в Delphi'йском ObjectPascal. Только там надо для каждого метода реализуемого интерфейса указать какой объект и какой его метод подставлять.
Здравствуйте neutrino, Вы писали:
N>я знаком с шарпом крайне поверхностно, но, если не ошибаюсь, он не поддерживает множественное наследование. N>к каким проблемам (и возможно преимуществам) это приводит и какие в нем есть альтернативные подходы.
А еще в C# нет шаблонов. Это тоже дает некоторые преимущества (программисту не нужно осваивать эту довольно непростую весчь), но и ряд недостатков. То же самое касается и множественного наследования реализации и управления памятью. MS решили, что программеры a-priori недостаточно внимательны и обучаемы (в каком-то смысле это верно) и решили все как можно сильнее упростить.
Но для особо продвинутых оставили лазейку: Managed C++.
Здравствуйте Ursus, Вы писали:
U>Честно говоря я пока не встречал реальных задач где бы требовалось множественное наследование классов.
ATL — великолепный пример использования множественного наследования в купе с шаблонами. Им можно отметать любые инсинуации против необходимости наличия множественного наследования (пусть будет наследования реализации, если хотите) и шаблонов в современных языках программирования.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, Вы писали:
IT>Здравствуйте Ursus, Вы писали:
U>>Честно говоря я пока не встречал реальных задач где бы требовалось множественное наследование классов.
IT>ATL — великолепный пример использования множественного наследования в купе с шаблонами. Им можно отметать любые инсинуации против необходимости наличия множественного наследования (пусть будет наследования реализации, если хотите) и шаблонов в современных языках программирования.
Прекрасный пример Умыли Хоть может и можно было бы поспорить наверное, но согласен.
Немного уйду в сторону, просто интересно, попадались ли кому задачи аналогичные решаемым ATL?
Здравствуйте Andy77, Вы писали:
A>Меня удивляет, что нигде в современных языках не встречается такая конструкция (ведь наследование реализации можно представить комбинацией аггрегации и делегирования) —
A>вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
Вот пример подобного на шарпе
namespace ConnectingImpl {
public interface Int1 {
string MethodA(string par1);
}
public class Impl1 : Int1 {
public string MethodA(string par1) {
return"Implementation 1 "+par1;
}
}
public interface Int2 {
string MethodB();
void MethodC();
}
public class Impl2 : Int2 {
public string MethodB() {
return"Implementation 2";
}
public void MethodC() {
System.Console.WriteLine("MethodC");
}
}
public class Test {
[Implements(typeof(Int1))]
public Impl1 impl1 = new Impl1();
[Implements(typeof(Int2))]
public Impl2 impl2 = new Impl2();
static void Main() {
ImplBuilder ib = new ImplBuilder(typeof(Test));
object conimpl = ib.CreateInstance(new Test());
System.Console.WriteLine(((Int1) conimpl).MethodA("X"));
System.Console.WriteLine(((Int2) conimpl).MethodB());
((Int2) conimpl).MethodC();
}
}
}
Здравствуйте VladD2, Вы писали:
VD>ATL — это стиль решения задач. Теже задачи решаются и другими способами. В том же Дельфи множественного наследования нет, а КОМ реализован.
Но с ATL'ем то приятнее работать, не так ли?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, Вы писали:
VD>>ATL — это стиль решения задач. Теже задачи решаются и другими способами. В том же Дельфи множественного наследования нет, а КОМ реализован.
IT>Но с ATL'ем то приятнее работать, не так ли?
Тебя не поймешь. То с Шарпом приятнее, то с АТЛ-ом. Ты давай ориентацию выбирай.
PS
Если серьезно, то АТЛ использует наследование в основном для подключения реализации. Тут можно было бы обойтись и более простыми мерами. Ведь за множественное наследование приходится платить половиной недостатков С++-а. Думаю, лучшим решением было бы добавить возможноть присоеденения реализации без множественного наследования. Синтаксис мы тут уже обсуждали.
PSS
За одно нужно добавить шаблоны, const для параметров и локальных переменных... Куда? Думаю ты понял.
Здравствуйте AndrewVK, Вы писали:
AVK>Здравствуйте Andy77, Вы писали:
A>>Меня удивляет, что нигде в современных языках не встречается такая конструкция (ведь наследование реализации можно представить комбинацией аггрегации и делегирования) —
AVK> A>>вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
AVK>Вот пример подобного на шарпе
Хм... оценку я тебе уже поставил, а пример не компилируется признавайся, откуда нужно брать этот таинственный Implements ?
Здравствуйте VladD2, Вы писали:
VD>Тебя не поймешь. То с Шарпом приятнее, то с АТЛ-ом. Ты давай ориентацию выбирай.
Да я уже выбрал, причём в отличии от Мишки.ex.NET я таки убедил народ в правильности моего выбора
VD>Если серьезно, то АТЛ использует наследование в основном для подключения реализации. Тут можно было бы обойтись и более простыми мерами. Ведь за множественное наследование приходится платить половиной недостатков С++-а. Думаю, лучшим решением было бы добавить возможноть присоеденения реализации без множественного наследования. Синтаксис мы тут уже обсуждали.
Я в своей реплике как раз про это и намекал, зная что обязательно будут инсинуации
VD>За одно нужно добавить шаблоны, const для параметров и локальных переменных... Куда? Думаю ты понял.
Кстати, в MC++ кое что уже из этого есть (я про использование реализации). В нём, если класс или его предки имеет метод с таким же названием и сигнатурой, то он по умалчанию используется для имплементации метода интерфейса.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте Andy77, Вы писали:
A>Хм... оценку я тебе уже поставил, а пример не компилируется признавайся, откуда нужно брать этот таинственный Implements ?
Здравствуйте Andy77, Вы писали:
A>Хм... оценку я тебе уже поставил, а пример не компилируется признавайся, откуда нужно брать этот таинственный Implements ?
using System;
using System.Reflection;
using System.Collections;
using System.Text;
using System.CodeDom.Compiler;
namespace ConnectingImpl {
[AttributeUsage(AttributeTargets.Field)]
public class ImplementsAttribute : Attribute {
private Type intf;
public Type Interface {
get {
return intf;
}
}
public ImplementsAttribute(Type i) {
intf = i;
}
}
public class BaseImplementor {
public object ImplClass;
}
public class ImplBuilder {
private class Implementation {
public Type Interface;
public FieldInfo Field;
public Implementation(Type i, FieldInfo f) {
Interface = i;
Field = f;
}
}
private Assembly CompiledAssembly;
public ImplBuilder(Type ic) {
ArrayList il = new ArrayList();
//retreiving list of implementation fieldsforeach(FieldInfo fi in ic.GetFields()) {
ImplementsAttribute ia = (ImplementsAttribute) Attribute.
GetCustomAttribute(fi,typeof(ImplementsAttribute));
if(ia == null)
throw new ArgumentException("No any fields marked [Implements] found");
else {
il.Add(new Implementation(ia.Interface,fi));
}
}
//Building implementor class
StringBuilder csrc = new StringBuilder();
csrc.Append("namespace ConnectingImpl.DynamicAssembly {\n");
csrc.Append(" public class "+ic.Name+"Implementor : ConnectingImpl.BaseImplementor");
foreach(Implementation impl in il)
csrc.Append(","+impl.Interface.FullName);
csrc.Append(" {\n");
foreach(Implementation impl in il)
foreach(MethodInfo mi in impl.Interface.GetMethods()) {
ParameterInfo[] pia = mi.GetParameters();
StringBuilder dl = new StringBuilder(), cl = new StringBuilder();
foreach(ParameterInfo pi in pia) {
if(dl.Length > 0) {
dl.Append(", ");
cl.Append(", ");
}
dl.Append(pi.ParameterType.FullName+" "+pi.Name);
cl.Append(pi.Name);
}
csrc.Append(" public ");
if(mi.ReturnType.FullName != "System.Void")
csrc.Append(mi.ReturnType.FullName);
else
csrc.Append("void");
csrc.Append(" "+mi.Name+"(");
csrc.Append(dl);
csrc.Append(") {\n");
if(mi.ReturnType.FullName != "System.Void")
csrc.Append(" return ");
else
csrc.Append(" ");
csrc.Append("(("+ic.FullName+") ImplClass)."+impl.Field.Name+"."+mi.Name+"(");
csrc.Append(cl);
csrc.Append(");\n");
csrc.Append(" }\n");
}
csrc.Append(" }\n");
csrc.Append("}");
//Compile class
ICodeCompiler cc = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add(ic.Assembly.Location);
cp.GenerateInMemory = true;
CompilerResults cr = cc.CompileAssemblyFromSource(cp,csrc.ToString());
Console.WriteLine(cr.NativeCompilerReturnValue);
CompiledAssembly = cr.CompiledAssembly;
}
public object CreateInstance(object ic) {
BaseImplementor i = (BaseImplementor) CompiledAssembly.CreateInstance(
"ConnectingImpl.DynamicAssembly."+ic.GetType().Name+"Implementor");
i.ImplClass = ic;
return i;
}
}
}
Здравствуйте Igor Trofimov, Вы писали:
A>>Меня удивляет, что нигде в современных языках не встречается такая конструкция A>>вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
IT>Нечто очень близкое есть в Delphi'йском ObjectPascal. Только там надо для каждого метода реализуемого интерфейса указать какой объект и какой его метод подставлять.
Такое там тоже есть (пометодно). Но есть и следующее:
создается проперть, возвращающая наследуемый интерфейс и декларируется, что именно она (проперть) и будет этот интерфейс реализовывать. Без шаманских штучек типа вызова компилятора.
Здравствуйте IT, Вы писали:
IT>Здравствуйте VladD2, Вы писали:
... VD>>За одно нужно добавить шаблоны, const для параметров и локальных переменных... Куда? Думаю ты понял.
IT>Кстати, в MC++ кое что уже из этого есть (я про использование реализации). В нём, если класс или его предки имеет метод с таким же названием и сигнатурой, то он по умалчанию используется для имплементации метода интерфейса.
Да, с одной стороны это зачастую очень удобно, а с другой стороны — немного противоречит общей тенденции шарпа заставлять программиста "явно выражать свои намерения".
Здравствуйте Eugene Hrulev, Вы писали:
EH>Здравствуйте Igor Trofimov, Вы писали:
A>>>Меня удивляет, что нигде в современных языках не встречается такая конструкция A>>>вроде бы, и код чистый, понятный, хорошая возможность code reuse, присутствует наследование реализации, множественное наследование, как таковое, отсутствует... нет в жизни счастья.
IT>>Нечто очень близкое есть в Delphi'йском ObjectPascal. Только там надо для каждого метода реализуемого интерфейса указать какой объект и какой его метод подставлять.
EH>Такое там тоже есть (пометодно). Но есть и следующее:
EH>создается проперть, возвращающая наследуемый интерфейс и декларируется, что именно она (проперть) и будет этот интерфейс реализовывать. Без шаманских штучек типа вызова компилятора.