2012-08-12 73 views
0

我有一系列的接口定义,所有这些接口定义都被编译(所以我的对象编写正确)。如预期的那样,这些对象实例化。然而,当我试图从它的底层的工厂返回对象,我得到了以下错误:为什么我不能将我的对象作为其接口返回?

错误:

Unable to cast object of type 'SampleLibrary.Domain.DataAcessors.Person.SQLDataAccessor' to type '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."); 
    } 
} 

UPDATE:
请记住,IDataAccessorModel可以通过要定义任何所需的数据访问类型使用。

+0

如何声明Person.SQLDataAccessor()? – 2012-08-12 15:18:08

回答

0

这对我的工作,如果我宣布SQLDataAccessor这样的:

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

你可能会调用它像这样

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

即你叫TSqlServer。如果您在SQLDataAccessor中声明TIAccessType,则不能保证IAccessType将是SqlServer。因此铸造错误。 (但是,SqlServer保证为IAccessType,因为它可能实现它。)

+0

是的,我确实“试图”按照上面的描述来调用它。而且......我可以创建实例......这是失败的回报。感谢您的帮助。 – 2012-08-12 16:08:45

+0

当我运行代码时,'da'确实被创建并返回。从'IDataAccessorModel '而不是'IDataAccessorModel '派生'SQLDataAccessor'。 – 2012-08-12 16:22:24

+0

非常感谢!我知道我很亲密。 – 2012-08-12 16:35:04

1

SQLDataAccessor implements IDataAccessorModel<IPerson, IAccessType>,所以只有在<I, T><IPerson, IAccessType>时才有效。对此没有任何保证,因为该方法是通用的,而且I和T可以是任何类型,所以投射失败。

当然,由于您正在检查I和T的类型,您知道该转换将是有效的,但编译器不会。你可以欺骗它是这样的:

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

然而,由于TSqlServer,它没有任何意义,使其泛型类型参数。由于I必须实施IPerson,因此应该有一个约束。因此,该方法的签名应该是:

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

我试图使FactoryDataAccess“一般”返回IDataAccessor的各种实例。谢谢你的帮助。 – 2012-08-12 16:17:29

0

SQLDataAccessor不是一个通用类,但实现IDataAccessorModel<IPerson, IAccessType>准确,所以你的方法Create应该返回IDataAccessor<IPerson, IAccessType>,但你可能与其他泛型类型的说法。

更改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 
0

你有它的方式,I可以是任何从IPersonT派生的类型正是SqlServer类型,这会导致演员失败,因为SQLDataAccessor使用不同的参数实现IDataAccessorModel。您将需要有一个更准确的演员,如:

return (IDataAccessorModel<IPerson, IAccessType>)accessor; 
+0

'Common.Contracts.DataAccessors.IDataAccessorModel '改为'Common.Contracts.DataAccessors.IDataAccessor '。存在明确的转换(您是否缺少演员?) – 2012-08-12 15:43:11

+1

@PrisonerZERO,如果您只支持特定类型,那么使其具有通用性有什么意义? – 2012-08-12 15:52:38

+0

@PrisonerZERO您可能需要为类型参数添加其他条件,如其他一些答案中的建议。另外,请看[协变/反变化](http://msdn.microsoft.com/en-us/library/dd799517.aspx);也许这就是你需要在你的界面中实现的东西。 – mhusaini 2012-08-12 16:01:36

相关问题