使用System.Object时,对泛型方法执行new()约束

时间:2009-12-08 12:50:01

标签: c# generics interface

我正在与两个第三方图书馆合作,并在解决这一特定问题的方式上绞尽脑汁。我正在实现一个接口,它将传递类型为object的对象,并且在大量调用中,我需要将它们传递给一个泛型方法,该方法需要一个具有类和new()约束的类型定义

我知道我通过的任何对象都会遇到这些约束,但据我所知,我没有简单的方法可以指定一个对象满足这些条件的泛型方法。接口不能指定构造函数的约束,并且不允许抽象类作为泛型方法的类型参数。

在这种情况下传入的对象是由我知道和控制的,但是两个Delete方法的签名都无法修改。理想情况下,我只能实现一个保证无参数构造函数标准的接口,但这似乎不是一个选项。

这是我正在谈论的一个例子:

public void Delete(object toDelete) {
    _repo.Delete(toDelete)  // signature here is _repo.Delete<T>(T obj) where T : class, new()
}

为了给出一些背景知识并希望解释一下 - “删除”调用是ADO.NET数据服务中IUpdatable的实现,而_repo.Delete<T>调用来自SubSonic。我有一个DataContextProvider类将为我通过模型公开的每个类处理这些请求(以及其他类似的请求),因此直接转换为特定类是不可行的。我可以保证类总是类,并且有一个无参数构造函数,但是我不能说DataContext只有一组固定的类可以传递下来 - 理想情况下我喜欢{{1}无需修改即可使用新类。

4 个答案:

答案 0 :(得分:3)

您需要使用反射,您需要获取方法的MethodInfo对象以在您的存储库上调用,并动态调用它。

请注意,可能有一种更简单的方法可以做到这一点,但听起来你已经尝试过这个,否则这将是明显的解决方案。

由于你的“_repo”变量必须属于特定类型,例如Repository<Employee>,你或许可以像这样投出它?

_repo.Delete(toDelete as Employee);
// or
_repo.Delete((Employee)toDelete);

或者,如果它是通用的:

_repo.Delete(toDelete as T);

如果这不是一个选项,由于你没有显示的代码,你需要求助于反思。

以下是示例:

using System;
using System.Reflection;

namespace ConsoleApplication14
{
    public class Program
    {
        static void Main(string[] args)
        {
            Dummy d = new Dummy();
            EntityType e = new EntityType();
            d.Delete(e);

            Console.In.ReadLine();
        }
    }

    public class EntityType
    {
        public EntityType()
        {
        }
    }

    public class Dummy
    {
        private Repository<EntityType> _repo = new Repository<EntityType>();

        public void Delete(object toDelete)
        {
            Type t = _repo.GetType();
            Type genericType = t.GetGenericArguments()[0];
            MethodInfo mi = t.GetMethod("Delete",
                BindingFlags.Public | BindingFlags.Instance,
                null, new Type[] { genericType }, new ParameterModifier[0]);

            // _repo.Delete(toDelete);
            mi.Invoke(_repo, new Object[] { toDelete });
        }
    }

    public class Repository<T>
        where T: class, new()
    {
        public void Delete(T value)
        {
            Console.Out.WriteLine("deleted: " + value);
        }
    }
}

答案 1 :(得分:2)

  

我知道我通过的任何物体都会遇到这些限制

它是一种公共方法。您不必担心传入的任何对象。您必须担心任何人传入的任何对象。

如果你知道对象符合这些约束,你还知道对象是什么类型的吗?如果是这样,那么只需将其转换为该类型。

答案 2 :(得分:1)

我认为这会重复您已经知道的内容,但如果您真的无法改变其中任何一种Delete方法,那么您就会陷入困境。

外部方法采用普通object作为参数,内部方法需要T参数,其中T符合class, new()约束。不幸的是,这两者无法在不做任何改动的情况下进行调和。

答案 3 :(得分:0)

您可以使用GetConstructors方法的反射来验证该类型是否具有无参数构造函数。这是你对new()约束的意思吗?