【问题标题】:c# Generics: Different Return Types using Genericsc# 泛型:使用泛型的不同返回类型
【发布时间】:2011-11-08 19:03:22
【问题描述】:

我有一个数据访问库,我想返回不同的数据格式(XML、Json、DataTable)。我试图使用泛型来实现这一点。

public interface IDBInteractor<T>
{
    T ExecuteDSQuery(string myQuery)
}

public class DBInteractorDT : IDBInteractor<DataTable>
{
    public DataTable ExecuteDSQuery(string myQuery)
    {
        return new DataTable();
    }
}

public class DBInteractorJson : IDBInteractor<JsonString>
{
    public JsonString ExecuteDSQuery(string myQuery)
    {
        return new JsonString();
    }
}

我无法调用正确的方法。理想情况下,我会声明类似

     SomeClass<DataTable> dt = new SomeClass<DataTable>();
     SomeClass<JsonString> js = new SomeClass<JsonString>();

     DataTable myDT = dt.ExecuteDSQuery(myQuery);
     JsonString myJson = js.ExecuteDSQuery(myQuery);

我不确定如何声明 SomeClass。我知道我可以做类似的事情

    public class SomeClass<T> where T : IDBInteractor <T>
    {
        public T ExecuteQuery(T dtobject, string myQuery)
        {
           return dtobject.ExecuteDSQuery(myQuery);
        }
    }

但我不想将对象实例 (dtobject) 传递给每个方法调用。

【问题讨论】:

  • 为什么DBInteractorJsonExecuteDSQuery返回字符串?它应该返回JsonString
  • 比较 SomeClass&lt;DataTable&gt; dt = new SomeClass&lt;DataTable&gt;();public class SomeClass&lt;T&gt; where T : IDBInteractor &lt;T&gt;。但是DataTable 不是IDBInteractor &lt;T&gt;

标签: c# generics interface return-type


【解决方案1】:

你到底想做什么?此代码工作正常:

using System.Data;

namespace ConsoleApplication7
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IDBInteractor<DataTable> dt = new SomeClass<DataTable>(new DBInteractorDT());
            IDBInteractor<JsonString> js = new SomeClass<JsonString>(new DBInteractorJson());
            /*
            or you can write 

            IDBInteractor<DataTable> dt = new DBInteractorDT();
            IDBInteractor<JsonString> js = new DBInteractorJson();

             */

            DataTable myDT = dt.ExecuteDSQuery("");
            JsonString myJson = js.ExecuteDSQuery("");
        }
    }

    public interface IDBInteractor<T>
    {
        T ExecuteDSQuery(string myQuery);
    }

    public class DBInteractorDT : IDBInteractor<DataTable>
    {
        #region IDBInteractor<DataTable> Members

        public DataTable ExecuteDSQuery(string myQuery)
        {
            return new DataTable();
        }

        #endregion
    }

    public class DBInteractorJson : IDBInteractor<JsonString>
    {
        #region IDBInteractor<JsonString> Members

        public JsonString ExecuteDSQuery(string myQuery)
        {
            return new JsonString();
        }

        #endregion
    }

    public class SomeClass<T> : IDBInteractor<T>
    {
        private IDBInteractor<T> interactor;

        public SomeClass(IDBInteractor<T> interactor)
        {
            this.interactor = interactor;
        }

        public T ExecuteDSQuery(string myQuery)
        {
            return interactor.ExecuteDSQuery(myQuery);
        }
    }

    public class JsonString
    {
    }
}

【讨论】:

  • 你说得对,我最初错误地调用了对象,例如: DBInteractorDT dt = new DBInteractorDT();
【解决方案2】:

如果你的泛型参数有一个无参数的构造函数,你可以创建一个新的 Object T();

但是你必须定义你的 T 必须有一个无参数的构造函数 使用通用约束 new() 来强制:

public class SomeClass<T> where T : IDBInteractor <T> , new()

【讨论】:

    【解决方案3】:

    你可以将 new() 约束添加到你的类定义中,这样你的类就变成了:

    public class SomeClass<T> where T : IDBInteractor <T>, new()
    {
        public T ExecuteQuery(string myQuery)
        {
           return new T().ExecuteDSQuery(myQuery);
        }
    }
    

    然后您可以在公共无参数构造函数中进行任何设置。

    【讨论】:

      【解决方案4】:

      您的SomeClass&lt;T&gt; 依赖于IDBInteractor&lt;T&gt;。您可以添加一个new() 约束,以便您可以在需要时在SomeClass&lt;T&gt; 中创建一个实例。

      但是为什么不使用依赖注入的力量呢?只需在SomeClass&lt;T&gt; 的构造函数中接受IDBInteractor&lt;T&gt; 作为参数?

      代码

      public class SomeClass<T> where T : IDBInteractor <T>
      {
          private IDBInteractor<T> _interactor;
      
          public SomeClass(IDBInteractor<T> interactor)
          {
              _interactor = interactor;
          }
      
          public T ExecuteQuery(string myQuery)
          {
             return _interactor.ExecuteDSQuery(myQuery);
          }
      }
      

      另见

      http://www.theserverside.com/news/1321158/A-beginners-guide-to-Dependency-Injection

      【讨论】:

        【解决方案5】:

        我同意 fix_likes_coding。如果您只想创建一个类来执行查询,则可以查看扩展方法。这可能不太适合方案,但如果您想保持简单,可能会有所帮助。

        public static class InteractorUtils
        {
            public static T ExecuteQuery(this IDBInteractor<T> interactor, string myQuery)
            {
                return interactor.ExecuteDSQuery(myQuery);
            }
        }
        

        你可以这样使用它:

        IDBInteractor<DataTable> dt = new DBInteractorDT();
        
        dt.ExecuteQuery("");
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-24
          • 1970-01-01
          • 2014-08-25
          • 1970-01-01
          • 2021-12-25
          • 2010-10-01
          相关资源
          最近更新 更多