C#:如何查找和创建满足多种类型约束的实例

发布于 2024-08-06 15:51:28 字数 556 浏览 11 评论 0原文

假设我有一个具有多种类型约束的通用方法,这个:

public static void DoSomethingAwesome<T>(T thing)
    where T : IThing, IAwesome, IComparable<T>
{
    ...
}

现在......我如何使用反射创建可以发送到那里的东西?

如果这只是一个约束,我知道我可以这样做:

var types = assembly
      .GetTypes()
      .Where(typeof (IThing).IsAssignableFrom)

foreach(var t in types)
    DoSomethingAwesome((IThing) Activator.CreateInstance(t));

但是,不能真正转换为多个接口......我到底该如何解决这个问题?你可以说我现在在这里迷失了方向:P

标题有点长而且复杂,因为我不知道该怎么称呼它,如果可以的话请改进

Say I have a generic method with multiple type constraints, this this:

public static void DoSomethingAwesome<T>(T thing)
    where T : IThing, IAwesome, IComparable<T>
{
    ...
}

Now.... how can I, using reflection, create something I can send in there?

If it was only one constraint I know I can do it like this:

var types = assembly
      .GetTypes()
      .Where(typeof (IThing).IsAssignableFrom)

foreach(var t in types)
    DoSomethingAwesome((IThing) Activator.CreateInstance(t));

But, can't really cast to multiple interfaces... how on earth can I solve this? You could say I am pretty much lost here now :P

Title got kind of long and complex as I wasn't sure what to call this, please improve if you can

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

阳光下的泡沫是彩色的 2024-08-13 15:51:28

要添加 Reed 和 Loren 关于查找合适类型的答案,请注意,您仍然无法通过强制转换来调用 DoSomethingAwesome,因为正如您所发现的,编译器不提供将实例化对象强制转换为多个接口的方法。您有两个选择:

  1. 创建新界面
    我很棒的可比的东西
    源自 IThing、IAwesome 和
    IComparable,有你的
    类型实现它,并转换为

  2. 通过调用 DoSomethingAwesome
    反射。为此,您将
    需要获取 MethodInfo 的
    DoSomethingAwesome 通用方法,
    然后打电话
    MethodInfo.MakeGenericMethod 与
    你的类型实现了所有三个
    接口。

(2)的例子:

Type type = sometype; // For example found using reeds method
MethodInfo mgeneric = typeof(Awesomeiser).GetMethod("DoSomethingAwesome");
MethodInfo mspecific = mgeneric.MakeGenericMethod(new [] { type });
mspecific.Invoke(null, new [] { type });

To add to Reed and Loren's answers about finding suitable types, note that you still won't be able to call DoSomethingAwesome by casting, because as you have found, the compiler doesn't provide a way to cast the instantiated object to multiple interfaces. You have two options:

  1. Create a new interface
    IAwesomeComparableThing which
    derives from IThing, IAwesome and
    IComparable<T>, have your
    types implement that, and cast to
    that.

  2. Invoke DoSomethingAwesome through
    reflection. To do this, you will
    need to get the MethodInfo for the
    DoSomethingAwesome generic method,
    then call
    MethodInfo.MakeGenericMethod with
    your type that implements all three
    interfaces.

Example of (2):

Type type = sometype; // For example found using reeds method
MethodInfo mgeneric = typeof(Awesomeiser).GetMethod("DoSomethingAwesome");
MethodInfo mspecific = mgeneric.MakeGenericMethod(new [] { type });
mspecific.Invoke(null, new [] { type });
戴着白色围巾的女孩 2024-08-13 15:51:28

我猜有一些原因你无法做到

var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom && typeof (IAwesome).IsAssignableFrom))

I'm guessing there's some reason you can't do

var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom && typeof (IAwesome).IsAssignableFrom))
那伤。 2024-08-13 15:51:28

您需要一个可以根据所有约束进行分配的类型。前两个很简单,但第三个有点棘手:

// Using
static bool IsIComparable(Type thing)
    {
        foreach (Type interfaceType in thing.GetInterfaces())
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof (IComparable<>))
            {
                Type[] arguments = interfaceType.GetGenericArguments();
                if (arguments.Length == 1)
                {
                    if (arguments[0] == thing)
                        return true;
                }
            }
        }
        return false;
    }


// This returns an enumerable of compatible types:
var types = assembly.GetTypes().Where( t => 
   typeof(IThing).IsAssignableFrom(t) &&
   typeof(IAwesome).IsAssignableFrom(t) &&
   IsIComparable(t) );

You need a type that's assignable from all of your constraints. The first two are easy, but the third is a bit trickier:

// Using
static bool IsIComparable(Type thing)
    {
        foreach (Type interfaceType in thing.GetInterfaces())
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof (IComparable<>))
            {
                Type[] arguments = interfaceType.GetGenericArguments();
                if (arguments.Length == 1)
                {
                    if (arguments[0] == thing)
                        return true;
                }
            }
        }
        return false;
    }


// This returns an enumerable of compatible types:
var types = assembly.GetTypes().Where( t => 
   typeof(IThing).IsAssignableFrom(t) &&
   typeof(IAwesome).IsAssignableFrom(t) &&
   IsIComparable(t) );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文