Bir ton kodu yazmak zorunda kalmadan özellik ayarlarını zincirlemek istiyorsanız, bunu yapmanın bir yolu kod oluşturma (CodeDom) kullanmak olacaktır. Yansıma özelliklerinin bir listesini almak için Yansıma'yı kullanabilirsiniz, oluşturmaya çalıştığınız sınıfı döndüren son Build()
yöntemiyle akıcı bir oluşturucu sınıfı oluşturun.
Özel araçların nasıl kaydedileceğiyle ilgili olarak tüm boilerplate nesnelerini atlayacağım - belgelerini bulmak oldukça kolay ama yine de uzun soluklu ve bunu ekleyerek çok fazla ekleyeceğimi sanmıyorum . Kodgen için ne düşündüğümü size göstereceğim.
public static class PropertyBuilderGenerator
{
public static CodeTypeDeclaration GenerateBuilder(Type destType)
{
if (destType == null)
throw new ArgumentNullException("destType");
CodeTypeDeclaration builderType = new
CodeTypeDeclaration(destType.Name + "Builder");
builderType.TypeAttributes = TypeAttributes.Public;
CodeTypeReference destTypeRef = new CodeTypeReference(destType);
CodeExpression resultExpr = AddResultField(builderType, destTypeRef);
PropertyInfo[] builderProps = destType.GetProperties(
BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo prop in builderProps)
{
AddPropertyBuilder(builderType, resultExpr, prop);
}
AddBuildMethod(builderType, resultExpr, destTypeRef);
return builderType;
}
private static void AddBuildMethod(CodeTypeDeclaration builderType,
CodeExpression resultExpr, CodeTypeReference destTypeRef)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
method.Name = "Build";
method.ReturnType = destTypeRef;
method.Statements.Add(new MethodReturnStatement(resultExpr));
builderType.Members.Add(method);
}
private static void AddPropertyBuilder(CodeTypeDeclaration builderType,
CodeExpression resultExpr, PropertyInfo prop)
{
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
method.Name = prop.Name;
method.ReturnType = new CodeTypeReference(builderType.Name);
method.Parameters.Add(new CodeParameterDeclarationExpression(prop.Type,
"value"));
method.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(resultExpr, prop.Name),
new CodeArgumentReferenceExpression("value")));
method.Statements.Add(new MethodReturnStatement(
new CodeThisExpression()));
builderType.Members.Add(method);
}
private static CodeFieldReferenceExpression AddResultField(
CodeTypeDeclaration builderType, CodeTypeReference destTypeRef)
{
const string fieldName = "_result";
CodeMemberField resultField = new CodeMemberField(destTypeRef, fieldName);
resultField.Attributes = MemberAttributes.Private;
builderType.Members.Add(resultField);
return new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), fieldName);
}
}
Bence bu should bunu hemen - Açıkçası denenmemiş, ama buradan nereye gittiğini türlerinin listesi ile doldurulan bir
CodeCompileUnit
derler (
BaseCodeGeneratorWithSite
devralmasını) bir Codegen oluşturmaktır. Bu liste, araçla kaydettiğiniz dosya türünden geliyor - bu durumda, muhtemelen oluşturucu kodu oluşturmak istediğiniz satır sınırlandırılmış bir liste listesiyle bir metin dosyası yapıyorum. Takımın bunu taramasını sağlayın, türleri yükleyin (önce montajları yüklemiş olabilir) ve bayt kodu oluşturun.
göründüğü gibi sert, ama zor değil ve işiniz bittiğinde böyle kod yazmak mümkün olacak: İnanıyorum
Paint p = new PaintBuilder().Red(0.4).Blue(0.2).Green(0.1).Build().Mix.Stir();
neredeyse tam istediğiniz şeydir.Kod nesil çağırmak için yapmanız gereken o türlerinin bir listesini, (en .buildertypes
diyelim) özel uzantılı aracı kayıt projenizde bu uzantılı bir dosya koyun ve koyun geçerli:
MyCompany.MyProject.Paint
MyCompany.MyProject.Foo
MyCompany.MyLibrary.Bar
Ve bunun gibi. Kaydettiğinizde, yukarıdaki gibi yazma ifadelerini destekleyen ihtiyaç duyduğunuz kod dosyasını otomatik olarak oluşturur.
Bu yaklaşımı, birkaç yüz farklı ileti türüyle son derece karmaşık bir ileti sistemi için kullanmıştım. Her zaman mesajı oluşturmak, bir grup özellik belirlemek, kanaldan göndermek, kanaldan almak, yanıtı serileştirmek, vb. Çok uzun sürüyordu. Bağımsız özelliklerin tümünü bağımsız değişken olarak alan ve doğru türden bir yanıtı geri alan tek mesajlaşma sınıfı. Bu herkese tavsiye edeceğim bir şey değil, ama çok büyük projelerle uğraşırken, bazen kendi sözdizimini icat etmeye başlamanız gerekiyor!
Aslında projelerimden birinde benzer bir yaklaşım var. –