简体   繁体   中英

c# Generics: Different Return Types using Generics

I have a Data access library which I would like to return different data formats (XML, Json, DataTable). I was trying to use Generics to achieve this.

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();
    }
}

I am having trouble invoking the correct method. Ideally I would to declare something like

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

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

I'm not sure how to declare SomeClass. I know I could do something like

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

But I don't want to have to pass an object instance (dtobject) to each method call.

if your generic parameter has a parameterless constructor you can create a new Object T();

but you have to define that your T has to have a parameterless constructor use the generic constraint new() to force that:

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

You could add the new() constraint to your class definition so your class becomes:

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

You can then do any set up in a public parameterless constructor.

Your SomeClass<T> has an dependency on IDBInteractor<T> . You could add a new() constraint so you can create a instance in SomeClass<T> whenever you need one.

But why don't use the power of depencency injection? Just accept a IDBInteractor<T> as a parameter at the constructor of SomeClass<T> ?

The code

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);
    }
}

See also

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

What exactly are you trying to do? This code works fine:

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
    {
    }
}

I agree with fix_likes_coding. If you only want to create a class to execute a query you may look at extension methods instead. This may not fit well in the scheme of things but might help if you wanted to keep things simple.

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

and you could use it like this:

IDBInteractor<DataTable> dt = new DBInteractorDT();

dt.ExecuteQuery("");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM