解惑

解己之惑,解人之惑

标签:c (第1页共2页)

反射获取集合中指定下标的元素

不废话了,直接上代码吧:

public static object GetElementFromCollection(object obj, int index)
{
Type type = obj.GetType();
if (type.IsArray)
{
return ((Array) obj).GetValue(index);
}
else
{
object[] attributes = type.GetCustomAttributes(typeof(DefaultMemberAttribute), true);
DefaultMemberAttribute attribute = (DefaultMemberAttribute) attributes[0];
String indexerName = attribute.MemberName;
type.GetProperties();
PropertyInfo pi2 = type.GetProperty(indexerName, new Type[] { typeof(int) });
return pi2.GetValue(obj, new Object[] {index});
}
}

用C#动态调用WebService

其实利用的都是前人的成果:C# – Dynamically Invoke Web Service At Runtime

这个文章的问题是没有提及需要认证的时候怎么办,但是后面很多回帖都问到了,总结下:

在读取WSDL的时候有几种方式,我使用的是:

WebClient client = new WebClient();

if (_needCredential)
{
client.Credentials = _credential;
}
Stream stream = client.OpenRead(WSDL);
XmlTextReader xmlreader = new XmlTextReader(stream);

//XmlTextReader xmlreader = new XmlTextReader(Uri);
ServiceDescriptionImporter descriptionImporter = BuildServiceDescriptionImporter(xmlreader);
Assembly library = CompileAssembly(descriptionImporter);

在真正生成WebService的Instance以后,需要设置Instance的几个Property:

if (_needCredential)
{
PropertyInfo preAuthenticate = GetRealType().GetProperty(“PreAuthenticate”);
preAuthenticate.SetValue(Result, true, null);
PropertyInfo url = GetRealType().GetProperty(“Url”);
url.SetValue(Result, Url, null);
CredentialCache cache = new CredentialCache();
Uri uri = new Uri(Url);
cache.Add(uri, “Basic”, _credential);
PropertyInfo credentials = GetRealType().GetProperty(“Credentials”);
credentials.SetValue(Result, cache, null);
}

测试框架

最近在做C#版的测试框架,目的其实是让QA不用写代码就可以测试API,QA需要写一些XML,然后交给这个测试框架运行。

设计其实比较直接,把功能测试中的一些概念抽取出来包装下就可以了,XML要人可读可写,然后能够直接转换为对应的类,免去解析的过程最好。

我提取出来的主要概念如下:

  • Library,对应的其实就是DLL,就像java中的jar一样,可以从指定的路径load,也可以从系统的GAC(windows特定的东西)里面load。
  • Instance,其实本来想叫Object,因为是关键字,只能取这个比较紧似的名字,另外,声明的也确实是对象的instance而不是对象定义。
    • List,集合类型,可以当成List或者Array用。
    • WebService,这个是Instance的子类可能有点怪,但是框架的工作机制是生成WebService的Stub的对应的类,所以其实也是Instance,只是有一些额外的属性。
  • Operation,其实就是操作了,有很多子类型:
    • Method,就是方法调用了
    • Verify,主要是为了做结果验证,其实也是Method,只不过掩盖了实现,我用的就是NUit的实现。
    • Task,Operation的集合,本来想加一个Function的,但是感觉Function和Task功能完全一样。Task就相当于功能测试或者单元测试的一个方法。
    • Express,表达式,主要是为了支持简单的字符串连接和数学运算。
    • Field,获取或者设置Instance的field,我掩盖了C#中的Property和Field的区别,只提供Field,两种都可以访问。
    • Loop,其实也是Operation的集合,但是会把集合中的Operation重复执行很多次,用于性能测试或者批量调用,会生成一个索引值供Operation引用生成不同的值。
    • Indexer,访问集合类型中的某个指定下标的元素,主要是因为C#没有像Java一样提供Get(int index)方法,否则这个完全没有,直接用Method 就可以实现了。
    • Finder,主要是简化了从集合类型中查找某个元素,框架没有提供if/else这样的逻辑控制,只能提供这个变向的方式。
    • Wait,主要是提供Sleep以及异步调用支持,是Verify的子类型,可以每隔一段时间Verify一下,看看结果是不是match,然后有超时,超时就认为Veirfy失败。
  • Define,就是组件声明,里面包含的就是上面提到的那些东西。
  • Suite,就是Test Case了,包含Define列表和Task列表,以及Startup/Teardown

基本上已经涵盖测试中需要的大部分内容了。

一些额外的想法,Operation还是有很大扩展余地的,例如可以支持外部调用,例如调用一个命令行或者其它的程序。

反射创建一个指定类型的List

由于最近在做C#版的测试框架,所以对C#的反射研究得比较多一点,这里是另外一个心得,由于运行时才知道类型,所以如何创建一个指定类型的List?其实很简单:

Type elementType = realType;
Type listType = typeof(List<>);
Type typedListType = listType.MakeGenericType(elementType);

c#反射之Enum篇

因为最开始就遇到这个问题,所以单独提出来,不废话了,上代码吧

Assembly assembly = Assembly..Load(“MyDLL”);
Type type = assembly.GetType(“MyDLL.MyEnum”);
FieldInfo enumItem = type.GetField(“ENUM_TEST”);
object enumValue= Enum.ToObject(type, enumItem.GetValue(type));
最后一行代码得到的就是对应的enum对象的实例,可以传递给方法调用,type.GetField方法中的字符串其实就是enum中的字符串名字。要得到这个名字的列表也很容易:

string[] names = Enum.GetNames(type);

c#反射入门篇

主要就是几点

加载DLL

通过Assembly类的方法,主要是Load,还有其他一些方法可以自己研究下,Load方法可以传一个简单名,也可以传完整的限定名,传简单名(MyDLL)的时候,对应的DLL文件(MyDLL.dll)必须位于当前目录?(或者是PATH里面),如果是引用系统注册的DLL,则必须是完整的限定名,例如:MyDLL, Version=1.0.0.0, Culture=Neutral, PublickeyToken=d3cc2ceeafb73bc1

得到Type

这个没有什么,调用上面得到Assembly实例的GetType就行了

创建实例

得到Type以后,使用Activator.CreateInstance就可以了

调用方法

通过Type的GetMethod得到需要调用的MethodInfo对象,然后调用MethodInfo的Invoke方法。

废话少说,看代码吧:

Assembly assembly = Assembly..Load(“MyDLL”);
Type type = assembly.GetType(“MyDLL.MyClass”);
object obj = Activator.CreateInstance(type);
MethodInfo createMethod = type.GetMethod(“MyMethod”);
object[] parameters = new object[1];
parameters[0] = “ParameterValue”
object result = createMethod.Invoke(obj, parameters);

其实和Java差不多,就是java不需要load那一步,因为默认是从CLASSPATH中的所有jar中都可以load的,这个是JVM做的事情。如果需要load其他的不在CLASSPATH中的jar也是可以的,比较麻烦而已。

研究c#的反射机制

要做一个通用的自动测试框架,通过写xml文件完成Test Case的构建,由于打算支持COM和普通的DLL的方法调用,所以必须基于反射来做了。

大概看了下,好像也不是很复杂,就是得一步一步的试了。

从CDO得到Mailbox的大小

前几天的方案都比较复杂一些,再来一个简单的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MAPI;

namespace ConsoleApplication3
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            Session session = new Session();
            session.Logon(null, null, false, true, 0, true, "exchange2007\nuser1");
            InfoStores infoStores = (InfoStores)session.InfoStores;
            for (int i = 0; i < (int)infoStores.Count; i++)
            {
                InfoStore infoStore = (InfoStore)infoStores.get_Item(i + 1);
                if (((string)infoStore.Name).IndexOf("Mailbox – ") >-1)
                {
                    Fields fields = (Fields)infoStore.Fields;
                    Field size = (Field)fields.get_Item(CdoPropTags.CdoPR_MESSAGE_SIZE, System.Reflection.Missing.Value);
                    Field count = (Field)fields.get_Item(CdoPropTags.CdoPR_CONTENT_COUNT, System.Reflection.Missing.Value);
                    Console.WriteLine(infoStore.Name + ": " + size.Value + "Bytes, messages:" + count.Value);
                }
            }
            session.Logoff();
            Console.ReadLine();
        }
    }
}

这个方案的问题是需要安装CDO,好在这个东东是微软的,而且很小,安装包才几百K,其实就是把MAPI的一些API包装成COM了,所以.net平台的那些语言都可以调。

历史遗留问题是微软的死穴

向后兼容性和历史上的诸多古老的解决方案对于微软阵营的开发者而言就是梦魇,它的多语言支持又是另外一个败笔。

我现在被迫从Java阵营临时到了微软阵营,但是遇到的问题多多。
现在有几个比较简单的任务:得到Exchange Server的邮件大小,Exchange本身没有API做这个事情,但是有一些其他的变通方式,例如得到所有的Mailbox然后统计每个Mailbox的大小,而Mailbox的大小也没有直接的API,需要统计所有的Folder的大小,虽然性能上不太好,但是总归是可以做到的。
目前发现的解决方案有这样几个:

  • 使用Exchange 2007的management shell带的Get-MailboxStatistics脚本,我们可以得到Exchange的某个Database的大小,但是缺点是需要在Exchange Server上运行,优点是可以很容易写出C#的代码。
  • 使用Exchange 2007的EWS,优点是可以写出C#代码,而且可以从其他机器运行,缺点是只支持2007版本
  • 使用MAPI32,问题是只能写c++代码,尝试使用DllImport直接使用MAPI32,但是到HrOpenExchangePrivateStore就出问题了,内存读写有问题,MAPIInitialize,MAPILogon,MAPILogoff等方法就没事。网上看到有人用c#封装了MAPI32,但是没有涉及到HrOpenExchangePrivateStore。

接下来只能尝试写COM组件把它包起来给c#用了。

从Exchange2007得到Mailbox的大小

开始的时候觉得这个是一个很小的问题,肯定有API直接可以拿到的,不过看了一圈下来,给出的最多的建议是从MAPI得到Mailbox,然后遍历目录累加大小得到Mailbox的大小。可以参考微软的KB:
http://support.microsoft.com/kb/320071
http://support.microsoft.com/kb/200160/

不过感觉都很麻烦。Exchange 2007提供了Exchange Management Shell ,里面有个脚本命令Get-MailboxStatistics可以得到Mailbox的信息,其中就包括Mailbox的大小,然后可以用c#调用这个脚本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
            PSSnapInException snapInException = null;
            PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);
            Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
            myRunSpace.Open();
            Pipeline pipeLine = myRunSpace.CreatePipeline();
            Command myCommand = new Command("Get-MailboxStatistics");
            pipeLine.Commands.Add(myCommand);
            CommandParameter databaseParam = new CommandParameter("database", "Main Database");
            myCommand.Parameters.Add(databaseParam);
            Collection<PSObject> commandResults = pipeLine.Invoke();
            foreach (PSObject cmdlet in commandResults)
            {
                Console.WriteLine(cmdlet.Properties["DisplayName"].Value + "\t" + cmdlet.Properties["TotalItemSize"].Value);
            }
        }
    }
}

唯一的问题是这个需要在exchange server上执行,而且也不排除这个脚本也是通过遍历目录得到的大小(执行的速度似乎也不快)。

更早的文章

© 2019 解惑

本主题由Anders Noren提供向上 ↑