Skip to content

Instantly share code, notes, and snippets.

@ritalin
Forked from anonymous/PropertyTagMapper.cs
Created April 19, 2012 04:04
Show Gist options
  • Save ritalin/2418469 to your computer and use it in GitHub Desktop.
Save ritalin/2418469 to your computer and use it in GitHub Desktop.
A helper class to extract property-names of ViewModel for MVVM.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Samples {
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class PropertyCategoryAttribute : System.Attribute {
public PropertyCategoryAttribute(Type inTagType) {
this.Tag = inTagType;
}
public Type Tag { get; internal set; }
}
public class PropertyCategoryMapper {
public static PropertyCategoryMapper Create<TViewModel>() {
return new PropertyCategoryMapper(typeof(TViewModel));
}
public static PropertyCategoryMapper Create(Type inType) {
return new PropertyCategoryMapper(inType);
}
private Dictionary<Type, string[]> mTagMap;
private PropertyCategoryMapper(Type inType) {
mTagMap = (
inType.GetTypeInfo().DeclaredProperties
.Where(p => p.CanRead)
.SelectMany(p => {
return p.GetCustomAttributes<PropertyCategoryAttribute>(true).Select(attr => {
return new KeyValuePair<Type, string>(attr.Tag, p.Name);
});
})
.GroupBy(pair => pair.Key, pair => pair.Value)
.ToDictionary(pair => pair.Key, pair => pair.ToArray())
);
}
public string[] ToProprtyNames(Type inTag) {
return ToProprtyNamesCore(inTag);
}
public string[] ToProprtyNames<TCategoryTag>() {
return ToProprtyNamesCore(typeof(TCategoryTag));
}
private string[] ToProprtyNamesCore(Type inTag) {
string[] props;
if (mTagMap.TryGetValue(inTag, out props)) {
return props;
}
else {
return new string[0];
}
}
}
}
using System;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Samples {
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using NUnit.Framework.Constraints;
namespace Samples {
public class _PropertyTagに関するテストスイート {
[Test]
public void _プロパティ名の収集テスト() {
var vm = new PropertyCategoryTestViewModel();
var mapper = PropertyCategoryMapper.Create(vm.GetType());
string[] names;
names = mapper.ToProprtyNames<TestTag.Unknown>());
Assert.That(names.Length, Is.EqualTo(0), "TestTag.Unknownは未指定");
names = mapper.ToProprtyNames<TestTag.Numeric>());
Assert.That(names.Length, Is.EqualTo(3), "intとdoubleが対象");
Assert.That(names, Does.Contains("Value1"), "Value1は含む");
Assert.That(names, Does.Contains("Value2"), "Value2は含む");
Assert.That(names, Does.Contains("Num1"), "Num1は含む");
Assert.That(names, Does.Not.Contains("Text1"), "Text1は含まない");
Assert.That(names, Does.Not.Contains("CreatedAt"), "CreatedAtは含まない");
Assert.That(names, Does.Not.Contains("ModifiedAt"), "ModifiedAtは含まない");
names = mapper.ToProprtyNames<TestTag.Strings>());
Assert.That(names.Length, Is.EqualTo(1), "stringが対象");
Assert.That(names, Does.Contains("Text1"), "Text1は含む");
Assert.That(names, Does.Not.Contains("Value1"), "Value1は含まない");
Assert.That(names, Does.Not.Contains("Value2"), "Value2は含まない");
Assert.That(names, Does.Not.Contains("Num1"), "Num1は含まない");
Assert.That(names, Does.Not.Contains("CreatedAt"), "CreatedAtは含まない");
Assert.That(names, Does.Not.Contains("ModifiedAt"), "は含まない");
names = mapper.ToProprtyNames<TestTag.Dates>());
Assert.That(names.Length, Is.EqualTo(2), "DateTimeが対象");
Assert.That(names, Does.Contains("CreatedAt"), "CreatedAtは含む");
Assert.That(names, Does.Contains("ModifiedAt"), "ModifiedAtは含む");
Assert.That(names, Does.Not.Contains("Value1"), "Value1は含まない");
Assert.That(names, Does.Not.Contains("Value2"), "Value2は含まない");
Assert.That(names, Does.Not.Contains("Num1"), "Num1は含まない");
Assert.That(names, Does.Not.Contains("Text1"), "Text1は含まない");
names = mapper.ToProprtyNames<TestTag.Custom1>());
Assert.That(names.Length, Is.EqualTo(2), "CreatedAtとValue2フィールドが対象");
Assert.That(names, Does.Contains("CreatedAt"), "CreatedAtは含む");
Assert.That(names, Does.Contains("Value2"), "Value2は含む");
Assert.That(names, Does.Not.Contains("Value1"), "Value1は含まない");
Assert.That(names, Does.Not.Contains("Num1"), "Num1は含まない");
Assert.That(names, Does.Not.Contains("Text1"), "Text1は含まない");
Assert.That(names, Does.Not.Contains("ModifiedAt"), "ModifiedAtは含まない");
names = mapper.ToProprtyNames<TestTag.Custom2>());
Assert.That(names.Length, Is.EqualTo(3), "CreatedAtとNum1とText1フィールドが対象");
Assert.That(names, Does.Contains("CreatedAt"), "CreatedAtは含む");
Assert.That(names, Does.Contains("Num1"), "Num1は含む");
Assert.That(names, Does.Contains("Text1"), "Text1は含む");
Assert.That(names, Does.Not.Contains("Value1"), "Value1は含まない");
Assert.That(names, Does.Not.Contains("Value2"), "Value2は含まない");
Assert.That(names, Does.Not.Contains("ModifiedAt"), "ModifiedAtは含まない");
}
}
internal static class Does {
public static ConstraintExpression Not {
get {
return Is.Not;
}
}
public static ContainsConstraint Contains(string expected) {
return new ContainsConstraint(expected);
}
}
}
namespace TestTag {
public interface Unknown {}
public interface Numeric {}
public interface Strings {}
public interface Dates {}
public interface Custom1 {}
public interface Custom2 {}
}
internal class PropertyCategoryTestViewModel : INotifyPropertyChanged {
private PropertyCategoryMapper mMapper;
private DateTime mCreatedAt = DateTime.Now;
private DateTime mModifiedAt = DateTime.Now;
public PropertyCategoryTestViewModel() {
mMapper = PropertyCategoryMapper.Create(this.GetType());
}
public event PropertyChanged;
protected void OnPropertyChanged(string[] inNames) {
if (this.PropertyChanged != null) {
foreach (var name in inNames) {
this.PropertyChanged(name);
}
}
}
public void DoHoge() {
// Do something ...
this.OnPropertyChanged(mMapper.ToProprtyNames<TestTag.Numeric>());
}
[PropertyCategory(typeof(TestTag.Numeric))]
public int Value1 { get; set; }
[PropertyCategory(typeof(TestTag.Numeric))]
[PropertyCategory(typeof(TestTag.Custom1))]
public int Value2 { get; set; }
[PropertyCategory(typeof(TestTag.Numeric))]
[PropertyCategory(typeof(TestTag.Custom2))]
public double Num1 { get; set; }
[PropertyCategory(typeof(TestTag.Strings))]
[PropertyCategory(typeof(TestTag.Custom2))]
public string Text1 { get; set; }
[PropertyCategory(typeof(TestTag.Dates))]
[PropertyCategory(typeof(TestTag.Custom1))]
[PropertyCategory(typeof(TestTag.Custom2))]
public DateTime CreatedAt {
get {
return mCreatedAt;
}
}
[PropertyCategory(typeof(TestTag.Dates))]
public DateTime ModifiedAt {
get {
return mModifiedAt;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment