【问题标题】:Casting interface to concreate class at runtime via list of Types implementing interface在运行时通过实现接口的类型列表将接口转换为具体类
【发布时间】:2021-12-25 16:45:43
【问题描述】:

4 编辑。我现在意识到我的问题有缺陷,因为我很难解释它,所以它是有道理的。但经过更多阅读后,我发现了这个Statically Typed or Dynamically Typed,其中包含“ ...静态类型语言:

  • 每个表达式都是编译时已知的类型。
  • 变量仅限于编译时已知的类型”

创建/转换一个只有在运行时才知道的类型的变量基本上是我想知道的是否可以这样做。显然不是。即使我可以在运行时检查类型,我也无法创建该类型的变量。

除非我涉及动态类型并且在具体对象上有预定义的方法来返回自己..


这更像是一个“有可能”的问题,而不是“我需要这样解决它的帮助”...... 我有:

interface IFruit {}
class Apple : IFruit {}
class Pear: IFruit {}
class Banana: IFruit {}

class CuttingBoard
{
    public void Cut(Queue<IFruits> fruits) 
    {
        IEnumerable<Type> typesImplementingIFruit = ReflectionHelper.GetAllTypesThatImplementInterface<IFruit >(typeof(IFruit ).Assembly);

         while(fruits.Count != 0) 
         {
            var fruit = fruits.Dequeue();

           // can I somehow, cast fruit to the concrete class using the typesImplementingIFruit that contains all three concrete types ?

          // **2 Edit**, like this:
          foreach(var t in typesImplementingIFruit) 
          {
              if(fruit.GetType() == t) 
              {
                 var concrete = fruit as t;
                 break;
              }
          }
          // end of 2 Edit
        }
    }
}

我尝试了很多不同的概念,使用 TypeConverters 和 Reflection 结合 typesImplementingIFruit 和 IFruit dequeued 中的类型,但没有成功。

This is a similar post 但我看不出在我的情况下如何使用动态和/或作为迈向具体参考的一步会有什么好处。

为了防止它,我知道我可以使用“if (fruit is Apple)”或“switch(fruit) case Apple”,但这是一个不使用实现接口的类型列表的解决方案

1 编辑:

我不想扩展接口、使用抽象或其他有意义的方法,因为这会破坏示例。除非偏离路线,否则有可能获得具体的课程..

这感觉有点相似:reflection to call generic method,但它涉及调用方法而不是强制转换。

我目前的猜测是我的示例无法解决,如果这是答案,我很高兴,因此我可以继续前进:)

3 编辑。

我会尝试重新编码问题。

static void EatApple(Apple apple)
{ }

static void Main(string[] args)
{
    object apple = new Apple() { Size = 30 };
 
    EatApple(??apple??);
}

是否有可能在运行时以某种方式将对象变为苹果引用,以便我可以用作EatApple 的参数?

像这样,但在 Apple 中没有 self 方法

class Apple 
{
    public int Size;

    public Apple Self()
    {
        return this;
    }
}

class Program 
{
    static void EatApple(Apple apple)
    { }

    static void Main(string[] args)
    {
        object apple = new Apple() { Size = 30 };
        var sameApple = ((dynamic)apple).Self();

        EatApple(sameApple);
    }
} 

【问题讨论】:

  • 您认为如何将一个类型转换为该类型的实例?此外,您的应用程序中可能根本没有这种类型的实例。但是您始终可以通过Activator.CreateInstance&lt;T&gt; 方法创建一个新实例。这符合您的需求吗?
  • 对不起,但是你为什么不直接在IFruit 上声明东西来从多态性中受益
  • 按照@andriy 所指出的,您可以在IFruit 上声明每个水果必须实现的方法或属性(例如bool MustBePeeled { get; })。然后每个水果都会实现它们(例如,香蕉可能有public bool ShouldBePeeled =&gt; true;,而其他水果可能返回false。这比在类型上匹配switch 更简洁:switch (fruit.GetType()) { case Apple apple: DoSomethingWithApple(apple); break; etc
  • 如果您可以接受单继承,请将Fruit 设为抽象类,并为您可以对水果执行的各种操作提供默认实现。然后各种水果可以根据需要覆盖它们
  • @Dmitry - 我不知道,但我的感觉是这是不可能的 :) 如果我使用 CreateInstance 我不能选择通用版本(如果我错了,请纠正我),因此会留下一个 Object 类型的实例而不是接口。还是我错过了什么?

标签: c# interface casting


【解决方案1】:

在我的第 4 次编辑中,在问题的顶部,我找到了一个链接,基本上表明我的问题的答案是:

  • 没有。
  • 在静态类型语言中是不可能的。

感谢所有有帮助的 cmets 促使我寻找更多提问的方法 :)

【讨论】:

    【解决方案2】:

    部分是的,你可以,不,你不应该。 Getting all types that implement an interface 回答了您的问题,您需要扫描程序集以查找接口的实现者,然后根据该列表检查您的 fruit 实例。

    但您不应该需要这样的代码,除非您正在编写序列化程序或代码生成器。如果你有一个接受接口形式的输入的方法,你就不必关心谁实现了这个接口。

    如果您的CuttingBoard 承诺它可以Cut(IFruit fruit)(或IFruit 的集合),那么它知道如何剪切任何IFruit。在那种方法中,你不应该关心你会得到什么样的水果。它承诺它知道如何,并且知道如何基于 IFruit 接口的成员。它们要么具有确定刀或表面或水果种类的属性,要么水果本身具有它将调用的Cut(...) 方法。

    或者换个说法,如果您在这里知道tApple,但您的代码可能不知道Apple(因为它在一个完全不同的程序集中),那么您的其余代码将如何更改为使用tconcrete

    if(fruit.GetType() == t) {
        var concrete = fruit as t;
        break;
    }
    

    如果t 不是编译时已知类型或泛型类型,则无法在运行时确定vart

    【讨论】:

    • 嗨,我 100% 同意我不需要这个代码来做一些实际的事情,只是我有时会想这样做,我认为这是不可能的,但不知何故我仍然在思考这个话题。我添加了一个 3d 编辑,使用不同的代码,也许对这个问题更有意义?通过不同的程序集,您的意思是如果 IFruit 在一个程序集中而 Apple 在另一个程序集中?而如果代码只作为接口程序集就永远找不到匹配项?
    猜你喜欢
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多