Targeting .net 4.0, I'm trying to build the following classes:
public class ConfigurationElementCollection<TElement, TParent>
where TElement : ParentedConfigElement<TParent>, new()
where TParent : class
{
public TParent ParentElement { get; set; }
protected ConfigurationElement CreateNewElement()
{
//**************************************************
//COMPILER GIVES TYPE CONVERSION ERROR ON THIS LINE!
//**************************************************
return new TElement { ParentCollection = this };
}
}
public class ParentedConfigElement<TParent> : ConfigurationElement where TParent : class
{
internal ConfigurationElementCollection<ParentedConfigElement<TParent>, TParent>
ParentCollection { get; set; }
protected TParent Parent
{
get
{
return ParentCollection != null ? ParentCollection.ParentElement : null;
}
}
}
As the code comment above indicates, the compiler gives an error:
Cannot implicitly convert type 'Shared.Configuration.ConfigurationElementCollection<TElement, TParent>' to 'Shared.Configuration.ConfigurationElementCollection<Shared.Configuration.ParentedConfigElement<TParent>,TParent>
I don't expect this error, because the compiler also knows that TElement
is a Shared.Configuration.ParentedConfigElement<TParent>
due to the generic type constraint I specified.
Still, I figure I will expressly cast the type to get past this issue:
(ConfigurationElementCollection<ParentedConfigElement<TParent>,TParent>) this;
Unfortunately, I get the same compiler error. Why is this happening? What did I do wrong? And without resorting to dynamic
types, what can I do to fix this?
Based on https://stackoverflow.com/a/6529618/5071902
protected ConfigurationElement CreateNewElement()
{
return (TElement)Activator.CreateInstance(typeof(TElement), this);
}
You will need a constructor with this signature, setting the
ParentCollection
property.
You can try using reflection too. Take a look at this answer https://stackoverflow.com/a/6529622/5071902
Your problem is that you have a type CEC<A, B>
and you trying to assign it to a property of type CEC<C<A>,B>
which you can't do, in much the same way as List<string>
cannot be assigned to storage of type List<object>
even though string
derives from object
.
A clean solution without using implicit operators or dynamic is to use an interface:
public interface IConfigurationElementCollection<TParentedConfig, TParent>
where TParentedConfig : ParentedConfigElement<TParent>
where TParent : class
{
TParent ParentElement { get; }
}
public class ConfigurationElementCollection<TElement, TParent> : IConfigurationElementCollection<ParentedConfigElement<TParent>, TParent>
where TElement : ParentedConfigElement<TParent>, new()
where TParent : class
{
public TParent ParentElement { get; set; }
protected ConfigurationElement CreateNewElement()
{
//**************************************************
//COMPILER NO LONGER GIVES TYPE CONVERSION ERROR
//BECAUSE this IMPLEMENTS THE EXPECTED INTERFACE!
//**************************************************
return new TElement { ParentCollection = this };
}
}
public class ParentedConfigElement<TParent> : ConfigurationElement where TParent : class
{
internal IConfigurationElementCollection<ParentedConfigElement<TParent>, TParent>
ParentCollection { get; set; }
protected TParent Parent
{
get
{
return ParentCollection != null ? ParentCollection.ParentElement : null;
}
}
}
Since the property in ParentedConfigElement
is internal, you can also make the interface internal to avoid exposing this implementation detail to any consumers, if that sort of thing is a concern for you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.