Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C在未知泛型类型上调用方法_C#_Generics_Reflection - Fatal编程技术网

C# C在未知泛型类型上调用方法

C# C在未知泛型类型上调用方法,c#,generics,reflection,C#,Generics,Reflection,我有一个基类ManagerBase,它有一个通用的静态函数GetManager。有两个类继承自ManagerBase ManagerSomething1和ManagerSomething2。每个类都有一个静态函数GetManager,它返回继承的ManagerBase类型。我如何在不知道类型的情况下调用GetManager public class ManagerBase { public static T GetManager<T>(int managerID, bool

我有一个基类ManagerBase,它有一个通用的静态函数GetManager。有两个类继承自ManagerBase ManagerSomething1和ManagerSomething2。每个类都有一个静态函数GetManager,它返回继承的ManagerBase类型。我如何在不知道类型的情况下调用GetManager

public class ManagerBase
{
    public static T GetManager<T>(int managerID, bool withUsers, System.Func<SqlDataReader, T> del) where T : ManagerBase
    {
        T manager = del(dr);
        return manager;
    }
}

public class ManagerSomething1 : ManagerBase
{
    public static ManagerSomething1 GetManager<ManagerSomething1>(int managerID, bool withUsers)
    {
        return ManagerBase.GetManager<ManagerSomething1>(managerID, withUsers, dr => new ManagerSomething1(dr));
    }
}

public class ManagerSomething2 : ManagerBase
{
    public static ManagerSomething2 GetManager<ManagerSomething2>(int managerID, bool withUsers)
    {
        return ManagerBase.GetManager<ManagerSomething2>(managerID, withUsers, dr => new ManagerSomething2(dr));
    }
}

public static class SessionSharedHelper<T> where T : ManagerBase
{
    public static void InitializeSession(int managerID, bool withUsers)
    {
        SessionShared<T>.Manager = //I don't know how I can call ManagerBase.GetManager<T>(managerID, withUsers, ...);
    }
}

类似的方法可能会奏效:

MethodInfo method_info = typeof(T).GetMethod("GetManager",
   System.Reflection.BindingFlags.Static | BindingFlags.Public);
SessionShared<T>.Manager = 
   (T)method_info.Invoke(null, new object[]{managerID, withUsers, ...});

您可以重构为如下内容:

    public abstract class ManagerBase
    {
        public ManagerBase() { }

        public abstract void Initialize(int managerID, bool withUsers);
    }

    public class ManagerSomething1 : ManagerBase
    {
        public ManagerSomething1() 
        { }

        public override void Initialize(int managerID, bool withUsers)
        {
        }
    }

    public class ManagerSomething2 : ManagerBase
    {
        public ManagerSomething2()
        {
        }

        public override void Initialize(int managerID, bool withUsers)
        {
            throw new NotImplementedException();
        }
    }

    public static class SessionSharedHelper<T> where T : ManagerBase, new()
    {
        public static void InitializeSession(int managerID, bool withUsers)
        {
            T manager = new T();
            manager.Initialize(managerID, withUsers);
        }
    }

我认为您正试图在试图构建的类内部实现某种工厂模式

有两种方法可以实现:使用一个单独的类来知道如何构造Manager1和Manager2,或者让基类知道如何构造其每个子类。无论哪种方式,都需要了解每个子类。我认为没有一个好方法可以不经思考就完成你所拥有的

我可能会在一个单独的工厂类中实现类似的东西

public static T GetManager<T>(int managerID, bool withUsers) where T : ManagerBase
{
    if (typeof(T) == typeof(Manager1))
    {
        return new Manager1(managerID, withUsers) as T;
    }
    if (typeof(T) == typeof(Manager2))
    {
        return new Manager2(managerID, withUsers) as T;
    }

    throw new ArgumentException();
}

当你说给我managerID x的Manager*对象时,某个地方必须知道/决定要创建哪种类型的Manager类。因此,需要回答的一个问题是如何做出决定。这是由数据读取器返回的某种数据决定的吗

与使用GetManager静态方法不同,您可以创建一个manager工厂或存储库类,该类了解如何在给定数据读取器的情况下确定要创建哪种类型的manager对象

下面是一个示例实现。其思想是,在早期的某个时刻,例如应用程序启动时,创建一个ManagerRepository,然后为您拥有的每种类型的管理器类注册一个create委托。稍后,当您从ManagerRepository请求Manager对象时,它将决定返回哪种类型的Manager类,并将使用您为该类型注册的create委托

public class ManagerBase
{
}

class ManagerRepository
{
    private Dictionary<Type, Func<SqlDataReader, ManagerBase>> _ManagerCreateDelegates;

    public ManagerRepository()
    {
        _ManagerCreateDelegates = new Dictionary<Type, Func<SqlDataReader, ManagerBase>>();
    }

    public void RegisterCreate<T>(Func<SqlDataReader, ManagerBase> create)
        where T : ManagerBase
    {
        _ManagerCreateDelegates[typeof(T)] = create;
    }

    public ManagerBase GetManager(int managerID, bool withUsers)
    {
        SqlDataReader reader;
        reader = null;// TODO: obtain a data reader from somewhere...

        Type typeOfManager = this.DetermineManagerType(reader);

        Func<SqlDataReader, ManagerBase> create;
        if (_ManagerCreateDelegates.TryGetValue(typeOfManager, out create))
        {
            return create(reader);
        }
        else
        {
            throw new InvalidOperationException(string.Format("No create delegate has been registered for type [{0}].", typeOfManager.FullName));
        }
    }

    private Type DetermineManagerType(SqlDataReader reader)
    {
        // TODO: implement logic that uses the data reader to decide which type of Manager object to create
        throw new NotImplementedException();
    }
}

public class ManagerSomething1 : ManagerBase
{
    public ManagerSomething1(SqlDataReader reader)
    {
        // TODO: implement logic to construct ManagerSomething1 given a data reader
    }
}

public class ManagerSomething2 : ManagerBase
{
    public ManagerSomething2(SqlDataReader reader)
    {
        // TODO: implement logic to construct ManagerSomething1 given a data reader
    }
}

class Program
{
    static void Main(string[] args)
    {
        // create a ManagerRepository somewhere
        ManagerRepository repository = new ManagerRepository();

        // register create delegates for each type of Manager
        repository.RegisterCreate<ManagerSomething1>(dr => new ManagerSomething1(dr));
        repository.RegisterCreate<ManagerSomething2>(dr => new ManagerSomething2(dr));

        // use the repository
        int managerID = 5;
        bool withUsers = false;
        ManagerBase manager = repository.GetManager(managerID, withUsers);
    }
}

我不是很确定,但我有一种烦人的感觉,你正在尝试使用泛型,而基本多态性可以解决这个问题。你能解释一下决定你应该使用哪一种管理器的逻辑吗?没有真正的逻辑;SessionSharedHelper中定义的类型T与需要返回的类型相同。请告诉我该类型。如果OP坚持的话,你也可以让每个类都提供一个静态方法来给你del。我不确定这对我来说是如何工作的,因为InitializeSession函数只是用来检索管理器并将其粘贴到会话中。GetManager函数需要返回ManagerBase类型的对象。在InitializeSession中,T是从ManagerBase继承的对象。是的,它是一个ManagerBase。这就是我的想法,我开始在InitializeSession函数中编写if语句,编译器告诉我这两个条件都不能满足。在调试过程中,两个条件都不满足。很可能我遗漏了一些东西,这就是我在浏览器中而不是在VisualStudio中编写代码的原因。更正了cast与'as',异常的正确名称和括号数。您仍然应该考虑重构。这是一些严重的代码气味使用后期绑定从数据库填充对象?如果这不是一个玩具应用程序,我不推荐它。我同意,将此代码插入初始化会话不是最佳方法,我正在研究其他建议的解决方案。嗯。在重新阅读了这个问题之后,我意识到OP的情况需要一个比ManagerBase更具体的管理器类型,因此这可能不是解决这个特定问题的好方法。