通用方法和访问具体实例属性

时间:2014-12-17 14:54:20

标签: c# generics abstract

我有这些课程(只是一个例子):

/* Data classes */

public class Data
{
    public int Id { get; set; }
    ...
}

public InfoData<TInfo> : Data
    where TInfo: InfoBase
{
    public TInfo Info { get; set; }
    ...
}

/* Info classes */

// ABSTRACT
public abstract class InfoBase
{
    public int Id { get; set; }
    ...
}

public class ExtraInfo : InfoBase
{
    public IList<InfoBase> Related { get; set; }
}

// + other InfoBase inherited types

然后我有一个消耗Data(或任何继承的类型实例)的方法,但必须读取作为参数传递的实际对象实例的其他属性:

TData Add<TData>(TData data)
    where TData: Data
{
    TData result = Get(
        data.Id,
        ...
        // how do I get to this one?
        data.Related[0].Id
    );
}

我可以访问所有Data类属性,但是如何获得实际实例的其他属性,因为我不能仅仅转换为

data as InfoData<InfoBase>

因为InfoBase是抽象的,我也不能用一些继承的非抽象类型来改变抽象泛型,因为会有太多的东西要考虑......

问题

  1. 如果很少有继承的课程,我怎样才能获得Related属性?
  2. 有没有更好的方法来实现我的方法?

1 个答案:

答案 0 :(得分:0)

在转换为abstract时应该没有问题,你也可以添加接口定义并让你的类继承它们,例如:

public interface IRelated{
    IList<InfoBase>Related {get; set;}
}

public class ExtraInfo : InfoBase, IRelated
{
    public IList<InfoBase> Related { get; set; }
}

public class OtherInfo:IRelated{
    public IList<InfoBase> Related { get; set; }
}

并转换为接口而不是类:

ExtraInfo i = new ExtraInfo(){ Id = 5 };
var p = (InfoBase)i;
var q = (IRelated)i;
q.Related.Add(new ExtraInfo());

但是我可以在你的代码中看到其他问题:在Add方法中你输错了属性:

data.Related.Id

因为data.Related返回InfoBase的IList而不是InfoBase类本身。

编辑:

你必须更清楚你期望从相关(或什么是获取参数列表)获得什么。

编辑2:

这里是您的添加方法代码:

TData Add<TData>(TData data) where TData:Data
{
    var infoBase = data as InfoBase; //or IRelated as in my earlier samples
    TData result;
    if (infoBase != null)
    {
        result = Get(data.id, infoBase.Related[0].Id); //you can also use infoBase.Id as first param
    }
    else
    {
        result = Get(data.id, null); //whatever you need to pass to the method if there is no related item
    }
}

编辑3:

这里的工作代码:

public class Data
{
    public int Id { get; set; }
    //...
}

public class InfoData<TInfo> : Data
    where TInfo: InfoBase
{
    public TInfo Info { get; set; }
    //...
}

/* Info classes */

// ABSTRACT
public abstract class InfoBase
{
    public int Id { get; set; }
    //  ...
}

public interface IRelated
{
    IList<InfoBase> Related {get; set;}
}

public class ExtraInfo : InfoBase, IRelated
{
    public IList<InfoBase> Related { get; set; }
}

public class OtherInfo : InfoBase, IRelated
{
    public IList<InfoBase> Related { get; set; }
}

...

class MainClass
{
    public static TData Get<TData>(int id, int? related)
        where TData: Data
    {
        Console.WriteLine("id: {0}, related:{1}", id, related);
        return (TData)null;
    }

    public static TData Add<TData>(TData data)
        where TData: Data
    {
        return Get<TData>(data.Id,null);
    }

    public static TData Add<TData, TInfo>(TData data)
        where TData: InfoData<TInfo>
        where TInfo: InfoBase
    {
        var infoBase = data.Info as IRelated;

        if (infoBase == null)
            return Get<TData>(data.Id, null);

        return Get<TData>(data.Id, infoBase.Related[0].Id);
    }

    public static void Main(string[] args) {
        var i = new ExtraInfo {
            Id = 5,
            Related = new List<InfoBase> { new ExtraInfo { Id = 1 }}
        };

        var data = new InfoData<ExtraInfo> { Id = 100, Info = i };
        var result1 = Add<InfoData<ExtraInfo>, ExtraInfo>(data);
        var result2 = Add(data);
    }
}

但......整个代码看起来不太好:))

有几种可能的改进:

  • 您可以将Add方法移动到类Data中,然后覆盖
  • 您可以将相关的ID传递给add方法,而不是传递整个对象
  • 您可以重新考虑域名并检查您是否真的需要这么多的重载。