简体   繁体   English

使用System.Object时,对通用方法实现new()约束

[英]Fulfilling a new() constraint on a generic method when using System.Object

I'm working with two third-party libraries, and racking my brain over a way to solve this particular issue. 我正在使用两个第三方库,并为解决这个特定问题而绞尽脑汁。 I'm implementing an interface which will pass me objects of type object , and in a good number of the calls, I need to pass them into a generic method that expects a type with class and new() constraints defined. 我正在实现一个接口,该接口将为我传递object类型的object ,并且在大量调用中,我需要将它们传递给一个通用方法,该方法期望定义了class和new()约束的类型。

I know that any object I pass through will meet these constraints, but as far as I can see, there's no simple way I can specify to a generic method that an object satisfies these criteria. 我知道我通过的任何对象都将满足这些约束,但是据我所知,没有简单的方法可以为通用方法指定对象满足这些条件。 An interface can't specify constraints on constructors, and an abstract class isn't permitted as a type argument to the generic method. 接口无法在构造函数上指定约束,并且不允许将抽象类用作泛型方法的类型参数。

The objects being passed in in this case are known and controlled by me, but the signature of both Delete methods can't be modified. 在这种情况下,传入的对象是我已知的并由我控制,但是两个Delete方法的签名都无法修改。 Ideally I'd be able to just implement an interface guaranteeing the parameterless constructor criteria, but that doesn't seem to be an option. 理想情况下,我将能够实现一个保证无参数构造函数条件的接口,但这似乎不是一个选择。

Here's an example of what I'm talking about: 这是我正在谈论的示例:

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

To give some background and hopefully explain things - the "Delete" call is an implementation of IUpdatable in ADO.NET Data services, while the _repo.Delete<T> call is from SubSonic . 为了提供一些背景信息并希望解释一下,“删除”调用是ADO.NET数据服务中IUpdatable的实现,而_repo.Delete<T>调用来自SubSonic I have one DataContextProvider class that will be handling these requests (and other similar ones) for every class that I'm exposing through my model, so a direct cast to a specific class isn't feasible. 我有一个DataContextProvider类,它将为我通过模型公开的每个类处理这些请求(以及其他类似的请求),因此直接转换为特定类是不可行的。 I can guarantee that the classes always are classes and have a parameterless constructor, but I cannot say from the DataContext that there are only a fixed set of classes that may be passed down - ideally I'd like the DataContext to work with new classes without modification. 我可以保证这些类始终是类,并且具有无参数的构造函数,但是我不能从DataContext说只有一组固定的类可以向下传递-理想情况下,我希望DataContext与新类一起使用而无需修改。

You need to use reflection, you need to get the MethodInfo object for the method to call on your repository, and invoke it dynamically. 您需要使用反射,需要获取MethodInfo对象,该方法才能在存储库上调用并动态调用它。

Note that there could be a much simpler way to do this, but it sounds to me that you have tried this, otherwise it would be the obvious solution. 请注意,执行此操作的方法可能简单得多,但对我来说,您已经尝试过此方法,否则,这显然是解决方案。

Since your "_repo" variable must be of a specific type, like Repository<Employee> , you could perhaps just cast it, like this? 由于您的“ _repo”变量必须为特定类型,例如Repository<Employee> ,您也许可以像这样强制转换它?

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

or, if it's generic: 或者,如果是通用的:

_repo.Delete(toDelete as T);

If that's not an option, due to code you haven't shown, you need to resort to reflection. 如果这不是一个选择,则由于您未显示代码,您需要求助于反思。

Here's the example: 例子如下:

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

I know that any object I pass through will meet these constraints 我知道我通过的任何物体都将满足这些约束

Its a public method. 它是一种公共方法。 You don't have to worry about any object that you pass in. You have to worry about any object that anyone passes in. 你不必担心的,你不用担心, 任何人通过任何物体传递任何对象。

If you know that the object meets those constraints, do you also know what type the object is? 如果您知道对象符合这些约束,那么您是否还知道对象是什么类型? If so, then just cast it to that type. 如果是这样,则将其强制转换为该类型。

I suppose that this is repeating what you already know, but if you really can't alter either of those Delete methods then you're stuck. 我想这是在重复您已经知道的内容,但是如果您真的不能更改这两个Delete方法中的任何一个,那么您将陷入困境。

The outer method takes a plain object as an argument and the inner method requires a T argument where T meets the class, new() constraint. 外部方法将一个普通object作为参数,而内部方法则需要一个T参数,其中T满足class, new()约束。 Unfortunately, there's no way that those two can be reconciled without alterations. 不幸的是,没有任何办法,这两者是无法和解的。

You can use reflection with the GetConstructors method to verify that the type has a parameterless constructor. 您可以将反射与GetConstructors方法一起使用,以验证类型具有无参数的构造函数。 Is that what you mean by new() constraints? 那是new()约束的意思吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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