问题
I want to create an extendable nested structure and it seems like I should be able to do this using generics, though I may not be using them "properly".
I want to be able to create child classes from GroupType and/or OptionType. The problem is that I can't perform the new
operation on the generic types even though I specified they could only be of a certain base type.
Is there any way to do what I'm trying to do?
public class AllInfo<GroupType, OptionType>
where GroupType: GroupBase<OptionType>
where OptionType: OptionBase
{
public List<string> Names { set; get; }
public List<GroupType> Groups { set; get; }
public AllInfo()
{
DataSet ds = DatabaseRetreival();
this.Groups.add(new GroupType(ds["Name"], ds["Type"]));
}
}
public class GroupBase<OptionType>
where OptionType: OptionBase
{
public string Name { set; get; }
public string Type { set; get; }
public List<OptionType> Options { set; get; }
public GroupBase(string name, string type)
{
this.Name = name;
this.Type = type;
DataSet ds = DatabaseRetreival(this.Type);
this.Options.Add(new OptionType(ds["Name"]));
}
}
public class OptionBase
{
public string Name { set; get; }
public OptionBase(string name)
{
this.Name = name;
}
}
回答1:
You can't specify which constructors a generic class should have. The constructors are not inherited, so even if the base class that you specified has that constructor, a class that derives from it doesn't have to have that constructor.
The only constructor that you can require is the parameterless constructor:
where GroupType: GroupBase<OptionType>, new()
As that only let's you use the parameterless constructor, you would also use a virtual method for putting the data in the object, for example:
GroupType group = new GroupType();
group.Init(ds["Name"], ds["Type"]);
this.Groups.add(group);
回答2:
You have to specify the classes must have a default constructor.
where GroupType: GroupBase<OptionType>, new()
View this article and jump down to the section titled Generic Constraints.
回答3:
The compiler cannot allow that, because it cannot guarantee that the OptionType
has a constructor with the right signature. But you can pass a factory function instead of invoking the constructor directly:
public class Foo<T>
{
private List<T> myObjects;
public Foo(Func<string, T> factory))
{
myObjects = new List<T>();
foreach (string s in GetDataStrings())
myObjects.Add(factory(s));
}
}
So if you have a Bar
class with a constructor taking a string, you do this:
Func<string,Bar> barFactory = x => new Bar(x);
var foo = new Foo<Bar>(barFactory);
回答4:
The problem you have is foundationally based in very high amounts of class coupling that you are trying to mitigate with inheritance/generics. I suggest you re-examine why you feel this is necessary. This quest will eventually lead you to interfaces, service-based programming, and IoCs like Ninject or Castle Windsor.
However, if you want a quick fix that further increases code complexity (because you don't have non-complex options here aside from changing your coding philosophy), use an abstract/virtual method, maybe call it Bind(), instead of constructors.
[bolded for tl;dr]
来源:https://stackoverflow.com/questions/4136596/extending-using-c-sharp-generics