【问题标题】:Reflect A Class, Reproduce Methods in Interface And Implemented Class? [duplicate]反映一个类,重现接口中的方法和实现的类? [复制]
【发布时间】:2013-12-24 10:06:07
【问题描述】:

我正在使用 WCF,它使用接口、操作契约和所有爵士乐来公开相关方法。

但是,如果假设一个单独的类包含所有方法,并且基本上不必在实现所述接口的接口/类上编写相同的方法签名,它会使用一些巫术来自动使这些方法在接口/类。例如,考虑以下情况:

[ServiceContract]    
public interface IService {

    [OperationContract]
    List<Foo> SelectAllFoo(string id);    
}    

public class Service : IService {

    public List<Foo> SelectAllFoo(string id)
    {
        // this just calls same method from Helpers class, same sig    
        return Helpers.SelectAllFoo(id);
    }    
}

我有大约 500 种方法我必须向服务公开,并且将它们放入服务中需要大量的输入。所以,本质上,我希望有一种方法可以传递一个类,返回所有方法,然后或多或少地将它们“注入”到接口/类中。

【问题讨论】:

  • 看看impromptu-interface能不能满足你的需求
  • 看来这需要我拥有接口上的所有方法,不是吗?
  • 如果你使用像 CodeRush 或 Resharper 这样的工具,你可以在类上使用 Extract Interface 重构,它会从类中创建接口,但你仍然需要添加属性(其中你也许可以自动化)
  • 我在想办法利用反射,所以它可以处理所有事情。
  • 500 种方法?您是否考虑过您的架构可能需要重新设计?

标签: c# wcf reflection


【解决方案1】:

使用反射可以解决你的问题:

a) 使用反射枚举您感兴趣的类中的所有公共方法,例如:

var methods = typeof(SomeClass).GetMethods(BindingFlags.Instance | BindingFlags.Public);

b) 使用此列表将您的服务的源代码生成为字符串

StringBuilder source = new StringBuilder();
source.AppendLine("using System;");
source.AppendLine("using System.ServiceModel;");
source.AppendLine("[ServiceContract]");
source.AppendLine("public class DynamicService {");
// Here for each MethodInfo from list generate a method source like
foreach (var method in methods)
{
    if (method.ReturnType == typeof(void))
        continue;
    string parameters = string.Join(", ", method.GetParameters().Select(pi => string.Format("{0} {1}", pi.ParameterType.Name, pi.Name)));
    string arguments = string.Join(", ", method.GetParameters().Select(pi => pi.Name));
    source.AppendFormat("[OperationContract]");
    source.AppendFormat("public {0} {1}({2})", method.ReturnType.Name, method.Name, parameters);
    source.AppendFormat("{{   return ConsoleApplication.Helpers.{0}({1}); }}", method.Name, arguments);
}
source.AppendLine("}");

注意:您需要在这里进行一些过滤,例如过滤掉ToString 等。作为示例,我绕过了所有 void 方法。

c) 使用CSharpCodeProvider编译服务源:

CSharpCodeProvider codeProvider = new CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters param = new CompilerParameters();
param.GenerateExecutable = false;
param.GenerateInMemory = true;
param.ReferencedAssemblies.Add("System.Runtime.Serialization.dll");
param.ReferencedAssemblies.Add("System.ServiceModel.dll");
param.ReferencedAssemblies.Add("System.dll");
param.ReferencedAssemblies.Add("ConsoleApplication.exe");
CompilerResults result = codeProvider.CompileAssemblyFromSource(param, source.ToString());

注意:在这里您可以添加对包含您的帮助类的程序集的引用,在我的示例中为ConsoleApplication.exe

d) 将您的动态服务用作普通服务。例如,您可以自行托管它:

if (!result.Errors.HasErrors)
{
    Type type = result.CompiledAssembly.GetType("DynamicService");
    var instance = Activator.CreateInstance(type);

    Uri baseAddress = new Uri("http://localhost:80/hello");
    using (ServiceHost host = new ServiceHost(type, baseAddress))
    {
        ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
        host.Description.Behaviors.Add(smb);

        host.Open();

        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();

        // Close the ServiceHost.
        host.Close();
    }
}

e) 然后你就有了:

f) 如果您想在 IIS 中托管此服务,则必须提供您自己的自定义 ServiceHostFactory

【讨论】:

  • tyvm!非常棒的解释。
猜你喜欢
  • 2013-12-01
  • 2019-01-29
  • 1970-01-01
  • 1970-01-01
  • 2021-05-02
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 2020-04-02
相关资源
最近更新 更多