使用泛型类型接口Interface <interface>从类转换为Interface

时间:2016-09-20 18:22:17

标签: c# generics interface

我无法将一个类转换为它的基本接口。我有以下(简化):

public interface ITaxonomy
{
    string CommonName { get; set; }
    string ScientificName { get; set; }
}

public interface ITaxonomyHasChildren<TChild> : ITaxonomy where TChild : ITaxonomy
{
    ICollection<TChild> Children { get; set; }
}

public interface ITaxonomyHasParent<TParent> : ITaxonomy where TParent : ITaxonomy
{
    TParent Parent { get; set; }
}

我需要在我的VM中提取数据:

private void SelectedEntityChanged(ITaxonomy selectedEntity)
{
    CommonName = selectedEntity.CommonName;
    ScientificName = selectedEntity.ScientificName;

    Children = selectedEntity.GetType().GetProperty(nameof(ITaxonomyHasChildren<ITaxonomy>.Children))?
        .GetValue(selectedEntity) as ICollection<ITaxonomy>;

    Parent = selectedEntity.GetType().GetProperty(nameof(ITaxonomyHasParent<ITaxonomy>.Parent))?
        .GetValue(selectedEntity) as ITaxonomy;
}

Children部分不起作用,我假设是因为它不想从ICollection<MyClass>转换为ICollection<ITaxonomy>

我该如何做到这一点?

2 个答案:

答案 0 :(得分:4)

为了使其工作,您需要创建通用接口covariant。但由于ICollection<T>不具有协变性,因此如果您负担得起,则还需要将Children类型更改为IReadOnlyCollection<TChild>并删除设置者。

public interface ITaxonomyHasChildren<out TChild> : ITaxonomy where TChild : ITaxonomy
{
    IReadOnlyCollection<TChild> Children { get; }
}

public interface ITaxonomyHasParent<out TParent> : ITaxonomy where TParent : ITaxonomy
{
    TParent Parent { get; }
}

这也可以让你避免反思:

private void SelectedEntityChanged(ITaxonomy selectedEntity)
{
    CommonName = selectedEntity.CommonName;
    ScientificName = selectedEntity.ScientificName;

    Children = (selectedEntity as ITaxonomyHasChildren<ITaxonomy>)?.Children;
    Parent = (selectedEntity as ITaxonomyHasParent<ITaxonomy>)?.Parent;
}

示例类实现:

class Taxonomy : ITaxonomy, ITaxonomyHasChildren<Taxonomy>, ITaxonomyHasParent<Taxonomy>
{
    public string CommonName { get; set; }
    public string ScientificName { get; set; }
    public Taxonomy Parent { get; set; }
    public List<Taxonomy> Children { get; set; } = new List<Taxonomy>();
    IReadOnlyCollection<Taxonomy> ITaxonomyHasChildren<Taxonomy>.Children => Children;
}

答案 1 :(得分:2)

调用

selectedEntity.GetType()
     .GetProperty( nameof(ITaxonomyHasChildren<ITaxonomy>.Children) )
     .GetValue( selectedEntity )

是一种非常迂回的做事方式。

您不需要使用反射系统来完成基本的面向对象的东西。

此外,你的类型非常复杂,没有充分的理由。

请考虑一下:

public interface IParent<T> //note: general-purpose interface unrelated to taxonomies
{
    ICollection<T> Children { get; }
}

public interface IChild<T> //note: general-purpose interface unrelated to taxonomies
{
    T Parent { get; set; }
}

public interface ITaxonomy
{
    string CommonName { get; set; }
    string ScientificName { get; set; }
    IParent<ITaxonomy> AsParent {get; } //returns `null` if not a parent
    IChild<ITaxonomy> AsChild {get; } //returns `null` if not a child
}

IChild<ITaxonomy> selectedEntityAsChild = selectedEntity.AsChild;
if( selectedEntityAsChild != null )
{
    ITaxonomy parent = selectedEntityAsChild.Parent;
    ...
}

IParent<ITaxonomy> selectedEntityAsParent = selectedEntity.AsParent;
if( selectedEntityAsParent != null )
{
    ICollection<ITaxonomy> children = selectedEntityAsParent.Children;
    ...
}