【NetOffice】Rangeを返すメソッド・プロパティをまとめてみた。
- 2012.11.19 Monday
- 03:18
Source and Project
Excelのオートメーションの実装をする上で、必ず学習しなければならないのがセルの参照と操作だとおもうのですが、セルを参照する方法がやたらと多く、何がどこにあって、どういうセルを取得するのか、全体像が見えません。ということで、クラス間に点在するセルを参照するであろうメソッドやクラスをまとめてみることにしてみました。方法は簡単、ExcelApiをリフレクションを利用してRagenオブジェクトを返すメソッド・プロパティを収集するだけ、せっかくExcelもほんの少し扱えるようになったので、Excelに出力してみることにしてみます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NetOffice.ExcelApi;
namespace Art55.NetOfficeDemo20121119_001
{
class Program
{
static void Main()
{
var rangeType = typeof (Range);
var targetTypes = rangeType.Assembly
.GetModules()
.SelectMany(m => m.GetTypes())
.Where(m => !m.IsInterface)
.ToList();
var methodList = targetTypes
.SelectMany(t => t.GetMethods())
.Where(m => m.IsPublic)
.Where(m => m.ReturnParameter != null && m.ReturnParameter.ParameterType == rangeType)
.Select(m => new Info { ReflectedType = m.ReflectedType, Name = m.Name, MemberType = m.MemberType })
.Distinct();
var propertyList = targetTypes
.SelectMany(t => t.GetProperties())
.Where(m => m.CanRead)
.Where(m => m.PropertyType == rangeType)
.Select(m => new Info {ReflectedType = m.ReflectedType, Name = m.Name, MemberType = m.MemberType})
.Distinct();
var valueSeq = methodList
.Concat(propertyList)
.GroupBy(m => m.ReflectedType)
.SelectMany(m => m)
.Select(
m => new object[]
{
m.ReflectedType.FullName,
m.Name,
(m.MemberType == MemberTypes.Method ? "メソッド" : "プロパティ")
})
.SelectMany(o => o);
object[,] values = new object[] { "クラス名", "メンバー名", "メンバータイプ" }
.Concat(valueSeq)
.ToMultiArrary(3);
var application = new Application {Visible = true};
Worksheet worksheet = application.Workbooks.Add().Worksheets.OfType<Worksheet>().First();
Range top = worksheet.Cells.First();
Range printRange = worksheet.Range(top, top.Cells[values.GetLength(0), values.GetLength(1)]);
printRange.Value2 = values;
printRange.Columns.EntireColumn.AutoFit();
}
struct Info
{
public Type ReflectedType { get; set; }
public string Name { get; set; }
public MemberTypes MemberType { get; set; }
}
}
public static class Utils
{
public static IEnumerable<T[]> ToArrarySeq<T>(this IEnumerable<T> source, int count)
{
return source.ToGroupingSeq(
(value, index) => index / count,
seq => seq.ToArray());
}
public static IEnumerable<TGroup> ToGroupingSeq<T, TKey, TGroup>(this IEnumerable<T> source, Func<T, int, TKey> createKey, Func<IEnumerable<T>, TGroup> createInnerResult)
{
int rowIndex = 0;
return source
.GroupBy(value => createKey(value, rowIndex++))
.Select(group => createInnerResult(group));
}
public static T[,] ToMultiArrary<T>(this IEnumerable<T> source, int count)
{
IEnumerable<T> enumerable = source as T[] ?? source.ToArray();
return enumerable.ToMultiArrary(count, 0);
}
public static T[,] ToMultiArrary<T>(this IEnumerable<T> source, int count, int origin)
{
IEnumerable<T> seq = source as T[] ?? source.ToArray();
var result = (T[,])Array.CreateInstance(
typeof(T),
new[] { seq.Count() / count + (seq.Count() % count == 0 ? 0 : 1), count },
new[] { origin, origin });
int index = 0;
seq
.ToList()
.ForEach(value => result[index / count + origin, index++ % count + origin] = value);
return result;
}
}
}
実行すると
思ったよりも量が少なく、すでに把握しているものの多いことが分かったので、「なんじゃこりゃ!?」みたいなのをちまちま落ち葉拾いしていけば、いいのかなっと思います。なんか分かったら、自分以外は周知の事実であろうと、ここに書きます。
あと、ひとつ感想なのですが、NetOfficeを使う前までは、この手の調べ物は知りたい情報をカンマ区切りの文字列でコンソールに出力させて、それをコピーしてExcelに貼り付けてとやっていたのですが、Excelに直接出力した方が、何度も作業するのであれば、こちらの方が効率がいいかなとおもいました。まあ、効率が上がる一番の要因はLinq to objectのおかげなんですが・・・。
Source and Project