传递可以"适合"接口的C#参数,但实际上并没有实现它

Aar*_*sen 33 c# reflection class system.reflection

注意:我知道这在实践中是一个糟糕的主意; 我只是好奇CLR允许你做什么,目的是创建某种'在创建它后修改类'预处理器.

假设我有以下类,它在另一个程序集中定义,所以我无法更改它.

class Person {
    public string Greet() => "Hello!";
}
Run Code Online (Sandbox Code Playgroud)

我现在定义一个接口和一个方法,如下所示:

interface IGreetable {
    string Greet();
} 

// ...

void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
Run Code Online (Sandbox Code Playgroud)

该类Person没有明确的实现IGreetable,但它可以不对其方法进行任何修改.

有了这个,有什么方法,使用Reflection,DLR或其他任何东西,其中一个实例Person可以成功传递到PrintGreeting不修改上面的任何代码?

小智 28

尝试使用库Impromptu-Interface

[Impromptu-Interface]框架允许您使用静态接口包装任何对象(静态或动态),即使它没有从它继承.它通过在代理中发出缓存的动态绑定代码来实现此目的.

这允许你做这样的事情:

var person = new Person();
var greeter = person.ActLike<IGreetable>();
Run Code Online (Sandbox Code Playgroud)

  • 重点:像类似的方法一样,创建一个*new*对象/实例来包装/代理接口调用 - 这使得它成为*代理*而不是*'cast'*操作.有时这与其他假设/代码要求不兼容. (8认同)
  • 这很有希望.`ActLike`方法来自哪里?它是库提供的`object`的扩展方法吗? (2认同)

Joh*_*ner 7

您可以使用dynamic包装器对象自己连接它,但是在包装类中丢失了类型安全性:

class GreetableWrapper : IGreetable
{
    private dynamic _wrapped;
    public GreetableWrapper(dynamic wrapped)
    {
        _wrapped = wrapped;
    }

    public string Greet()
    {
        return _wrapped.Greet();
    }
}

static void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
static void Main(string[] args)
{
    PrintGreeting(new GreetableWrapper(new Person()));
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

  • 值得指出的是,你不需要动态,因为这是一个包装类,任何东西都可以在Greet()中,只要它返回一个字符串就可以实现接口. (2认同)

Jon*_*nna 6

这可能很快就会很容易.可以将类型类引入C#作为形状,您可以在其中定义类的特征和针对该形状的代码,然后使用任何匹配类型的代码,而不需要代码的作者声明任何内容,几乎如你所描述的那样

在C#中最接近的事,现在也许是如何foreach与具有一种类型的作品GetEnumerator()有一个返回类型的对象MoveNext()Current他们甚至不落实IEnumerable等,仅在这是一个内置的概念编译涉及,在这里你可以定义它们.

有趣的是,它还可以让您定义静态成员.