2012-08-12 72 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

相關問題