为什么我不能将我的对象作为其界面返回?

时间:2012-08-12 15:10:44

标签: c# generics interface

我有一系列接口定义,所有接口定义都是编译的(所以我的对象组合正确)。正如预期的那样,对象实例化。但是,当我试图从它的'基础工厂我收到以下错误:

错误:

  

无法转换类型的对象   ' SampleLibrary.Domain.DataAcessors.Person.SQLDataAccessor'输入   ' Common.Contracts.DataAccessors.IDataAccessorModel`2 [SampleLibrary.Contracts.Models.IPerson,SampleLibrary.Domain.DataAccessors.Types.SqlServer]'

请记住,我正在尝试将每个实例作为IDataAccessor接口返回。

CODE:

public interface IDataAccessor<I, T>
{
    T AccessType { get; }
}

public interface IDataAccessorModel<I, T> : IDataAccessor<I, T>
{
    I Instance { get; }

    IResult<string> Get(I instance);
    IResult<string> Add(I instance);
    IResult<string> Update(I instance);
    IResult<string> Delete(I instance);
}

public class SQLDataAccessor : IDataAccessorModel<IPerson, IAccessType>
{
    internal SQLDataAccessor(IResult<string> result)
    {
        _connectionString = "";
        _result = result;
    }

    private readonly string _connectionString;
    private IResult<string> _result;

    public IAccessType AccessType { get { return new SqlServer(); } }
    public IPerson Instance { get; private set; }

    public IResult<string> Add(IPerson instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Get(IPerson instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Delete(IPerson instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Update(IPerson instance)
    {
        Instance = instance;
        return _result;
    }
}

public class FactoryDataAccess : IFactoryDataAccess
{
    internal FactoryDataAccess() { }

    public IDataAccessor<I, T> Create<I, T>()
    {
        var model = typeof(I);
        var target = typeof(T);

        if (model.IsAssignableFrom(typeof(IPerson)))
        {
            if (target == typeof(SqlServer)) {

                var accessor = new Person.SQLDataAccessor(new Result());

                // This next line FAILS!
                return (IDataAccessorModel<I, T>)accessor;
            }
        }

        throw new NotSupportedException("Type " + target.FullName + " and Source " + model.FullName + " is not supported.");
    }
}

更新
请记住,您希望定义的任何所需DataAccess类型都可以使用IDataAccessorModel

4 个答案:

答案 0 :(得分:1)

SQLDataAccessor实施IDataAccessorModel<IPerson, IAccessType>,因此仅当<I, T><IPerson, IAccessType>时才有效。不能保证这一点,因为该方法是通用的,I和T可以是任何类型,因此转换失败。

当然,既然你正在检查I和T的类型,那么知道转换是有效的,但编译器没有。你可以这样欺骗它:

return (IDataAccessorModel<I, T>)(object)accessor;

但是,由于T SqlServer,因此将其作为通用类型参数没有意义。由于I必须实现IPerson,因此应该对其进行约束。所以方法签名应该是:

public IDataAccessor<I, T> Create<T>() where T : IPerson

答案 1 :(得分:0)

SQLDataAccessor不是通用类,但完全实现IDataAccessorModel<IPerson, IAccessType>,因此您的方法Create应该返回IDataAccessor<IPerson, IAccessType>,但您可能使用其他泛型类型调用它。 / p>

SqlDataAccessor更改为:

public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T>
{
    internal SQLDataAccessor(IResult<string> result)
    {
        _connectionString = "";
        _result = result;
    }

    private readonly string _connectionString;
    private IResult<string> _result;

    public T AccessType { get { return new SqlServer(); } }
    public I Instance { get; private set; }

    public IResult<string> Add(I instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Get(I instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Delete(I instance)
    {
        Instance = instance;
        return _result;
    }
    public IResult<string> Update(I instance)
    {
        Instance = instance;
        return _result;
    }
}

您可能希望将IT限制为接口,因此请添加where约束:

public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T> 
    where I : IPerson
    where T : IAccessType

答案 2 :(得分:0)

您拥有它的方式,I可以是从IPerson派生的任何类型,而T完全属于SqlServer类型,这会导致转换失败,因为{ {1}}使用不同的参数实现SQLDataAccessor。您需要更精确的演员表,例如:

IDataAccessorModel

答案 3 :(得分:0)

如果我这样声明SQLDataAccessor,它对我有用:

public class SQLDataAccessor : IDataAccessorModel<IPerson, SqlServer>
{
    ...
}

你可能会这样称呼它

var factory = new FactoryDataAccess();
var da = factory.Create<IPerson, SqlServer>();

即。您通过T SqlServer来调用它。如果您在T中将IAccessType声明为SQLDataAccessor,则无法保证IAccessTypeSqlServer。因此铸造错误。 (但是,SqlServer保证为IAccessType,因为它可能会实现它。)