How to set the value of a shared parameter with type binding in Autodesk Revit Architecture 2010? - api

I have a shared parameter UValue bound to the Wall type with TypeBinding in Autodesk Revit Architecture 2010.
I can easily access the parameter with:
Definition d = DefinitionFile.Groups.get_Item("groupname").Definitions.get_Item("UValue");
Parameter parameter = self.get_Parameter("UValue");
The value of this parameter can be looked at with
var u = parameter.AsDouble();
But when I do
parameter.Set(0.8);
I get an Error:
InvalidOperationException: Operation is not valid due to the current state of the object.
On inspection, the parameters ReadOnly property is set to false.

Ok, I have found the problem:
When using TypeBinding, the parameter is not in the Wall object itself, but in its WallType property. If you are doing this in a polymorphic way (not just walls, but also floors, roofs etc.), then you can use the Element.ObjectType property.
The code in the OP should thus have been:
Definition d = DefinitionFile.Groups.get_Item("groupname").Definitions.get_Item("UValue");
Parameter parameter = self.ObjectType.get_Parameter("UValue");
This is being called from an extension method, a rather neat technique for adding parameters to Revit objects.
Setting the parameter can thus be done like this:
public static void SetUValue(this Wall self, double uvalue)
{
Parameter parameter = self.ObjectType.get_Parameter("UValue");
if (parameter != null)
{
parameter.Set(uvalue);
}
else
{
throw new InvalidOperationException(
"Wall does not contain the parameter 'UValue'");
}
}

Related

How can I detect when a ReadOnly property has accidentally been passed by reference?

I'm working on a project which is written in VB.NET. The project has several Structures which used to have writable fields. I replaced all of those fields with read-only properties, and wrote functions for creating a copy of a structure that has one of its properties changed.
I was assuming that every part of the code that attempted to write to one of these properties would become an error, and then I could simply fix all the errors by making the code call the new functions. To my dismay, it turns out that if a ReadOnly property is accidentally passed into a ByRef parameter of a function, the compiler accepts this with no warning, and the value that's assigned is silently discarded!
Here's an example:
Structure Point
Public ReadOnly Property X As Integer
Public ReadOnly Property Y As Integer
End Structure
Module Module1
Sub IncreaseByOne(ByRef x As Integer)
x = x + 1
End Sub
Sub Main()
Dim point As New Point
IncreaseByOne(point.X)
Console.WriteLine($"point.X is {point.X}")
End Sub
End Module
I was hoping that the line IncreaseByOne(point.X) would throw an error, or at least a warning, since point.X is read-only and it doesn't make sense to pass it by reference. Instead, the code compiles with no warnings, and the value assigned to x inside of IncreaseByOne is silently discarded, and the program prints point.X is 0.
How can I detect all of the places in my code where a read-only property is passed into a function that takes it by reference? The only way I can think of is to go through every read-only property that I have, find all places where that property is used as a parameter, and look to see if that parameter is ByRef. That'll be very time-consuming, but if there's no other solution, then that's what I'll do.
I'm using Visual Studio 2019. I'm open to installing new software in order to do this.
That's really interesting. The VB.NET Compiler really tries to make a property look like a variable. Even if I explicitly declare the property as
Structure Point
Dim _x As Integer
ReadOnly Property X() As Integer
Get
Return _x
End Get
End Property
End Structure
The code compiles and executes as before. If the property setter is added, it even works correctly!
Structure Point
Dim _x As Integer
Property X() As Integer
Get
Return _x
End Get
Set(value As Integer)
_x = value
End Set
End Property
End Structure
With the above change, the program correctly prints 1.
Looking at the generated IL, we can see why:
IL_0009: ldloca.s point
IL_000b: call instance int32 VisualBasicConsoleTest.Point::get_X()
IL_0010: stloc.1 // Store returned value in local variable
IL_0011: ldloca.s // load address of that local variable (and pass to function call)
IL_0013: call void VisualBasicConsoleTest.Program::IncreaseByOne(int32&)
IL_0018: nop
IL_0019: ldloca.s point
IL_001b: ldloc.1 // Load contents of local variable again
IL_001c: call instance void VisualBasicConsoleTest.Point::set_X(int32) // and call setter
Even though we expect an error because a property is not a value (and a byref requires a value), the compiler fakes what we might have intended: He actually generates a call to the getter, stores the value on the stack, passes a reference to the stack(!) to the called function and then calls the setter with that value.
This works in this simple scenario, but I agree with the commenters above, this might be very confusing when looking at it in detail. If the property is actually a computed property, the outcome is just arbitrary (try implementing the getter as Return _x + 1...)
C# would throw an error here, because a property is not a value and hence cannot be used as an out or ref parameter.
As Craig suggested in this answer, I went ahead and wrote a custom analyzer to detect when this occurs. Now, I can simply do Analyze / Run Code Analysis / On Solution, and every place that the described problem occurs gets marked with a warning such as "The property 'point.X' is read-only and should not be passed by reference."
The entire analyzer is available on GitHub. I've copied the important part below:
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.SimpleArgument);
}
private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
SimpleArgumentSyntax node = (SimpleArgumentSyntax)context.Node;
SemanticModel semanticModel = context.SemanticModel;
if (!IsByRef(node, semanticModel))
return;
(bool isReadOnly, string symbolType) = IsReadOnly(node, semanticModel);
if (isReadOnly)
{
Diagnostic diagnostic = Diagnostic.Create(
Rule,
node.Expression.GetLocation(),
symbolType,
node.Expression.GetText());
context.ReportDiagnostic(diagnostic);
}
}
/// <summary>
/// Determine if the given argument is passed by reference.
/// </summary>
private static bool IsByRef(SimpleArgumentSyntax node, SemanticModel semanticModel)
{
ArgumentListSyntax argumentList = (ArgumentListSyntax)node.Parent;
if (argumentList.Parent is InvocationExpressionSyntax invocation)
{
SymbolInfo functionInfo = semanticModel.GetSymbolInfo(invocation.Expression);
if (functionInfo.Symbol is IMethodSymbol method)
{
IParameterSymbol thisParameter = null;
if (node.IsNamed)
{
thisParameter = method.Parameters.FirstOrDefault(parameter =>
parameter.Name == node.NameColonEquals.Name.ToString());
}
else
{
int thisArgumentIndex = argumentList.Arguments.IndexOf(node);
if (thisArgumentIndex < method.Parameters.Length)
thisParameter = method.Parameters[thisArgumentIndex];
}
// If we couldn't find the parameter for some reason, the
// best we can do is just accept it.
if (thisParameter == null)
return false;
RefKind refKind = thisParameter.RefKind;
if (refKind != RefKind.None && refKind != RefKind.In)
return true;
}
}
return false;
}
/// <summary>
/// Determine if the given argument is a read-only field or property.
/// </summary>
private static (bool isReadOnly, string symbolType) IsReadOnly(SimpleArgumentSyntax node, SemanticModel semanticModel)
{
string symbolType = "field or property";
bool isReadOnly = false;
if (node.Expression is MemberAccessExpressionSyntax memberAccess)
{
SymbolInfo memberInfo = semanticModel.GetSymbolInfo(memberAccess.Name);
if (memberInfo.Symbol is IPropertySymbol propertySymbol && propertySymbol.IsReadOnly)
{
symbolType = "property";
isReadOnly = true;
}
if (memberInfo.Symbol is IFieldSymbol fieldSymbol && fieldSymbol.IsReadOnly)
{
symbolType = "field";
isReadOnly = true;
}
}
return (isReadOnly, symbolType);
}
There isn't a way to catch this with the compiler. Even Option Strict On will allow passing a read-only property to a ByRef argument. This is defined to pass by copy-in/copy-out, and it's surprising to me that the copy-out part will compile even when the Property Set is inaccessible.
If you want to have an automated lint-type check for this, I would imagine that a custom analyzer could find it. I haven't worked with analyzers, so I don't have any specific suggestions for how to write one or set it up.
Otherwise, you're left to a manual check. As was noted in a comment, you can use the "Find All References" command from Visual Studio to help with it, but this will still require a manual review of every read-only property.

Generic C# method for RavenDB (5.3) to return property subset for any document type

I'm trying to create a generic C# method that can return just the Id & Description (string) properties for a particular document type in a generic BasicObject class. (Most of my document types have Id & Description properties).
The method would accept the document type and (presumably) an expression that would be passed as a parameter to the .Select part of the query definition. The expression would convert the document type to a BasicObject (Id & Description properties).
I've tried the method below but RavenDB doesn't understand the expression. Is it possible to do what I need or do I have to implement the method for each document type.
public Task<List<T>> GetAllDocs(Expression<Func<T, BasicObject> convertExpression)
{
var query = _session.Query<T>
.Select(doc => convertExpression(doc));
var results = await query.ToListAsync();
return results;
}

Velocity Eventhandler

in velocity, when you do $object.variable if it not be able to find the getter function to
access it or the getter returns a null. it will just show $object.variable explicitly on the page
I know there is a quiet reference, but I don't want to add ! sign to thousands of variables.
I have tried InvalidReferenceEventHandler, NullValueHandler they all didn't get called.
I wander is there a specific type of Eventhandler for this.
Many thanks
The above seems to be a valid choice as well. However here is another option:
public class AppSpecificInvalidReferenceEventHandler implements
InvalidReferenceEventHandler
{
private static final Logger LOGGER =
Logger.getLogger(AppSpecificInvalidReferenceEventHandler.class);
#Override
public Object invalidGetMethod(Context context, String reference,
Object object, String property, Info info)
{
reportInvalidReference(reference, info);
return "";
}
#Override
public boolean invalidSetMethod(Context context, String leftreference,
String rightreference, Info info)
{
reportInvalidReference(leftreference, info);
return false;
}
#Override
public Object invalidMethod(Context context, String reference, Object object,
String method, Info info)
{
if (reference == null) {
reportInvalidReference(object.getClass().getName() + "." + method, info);
} else {
reportInvalidReference(reference, info);
}
return "";
}
private void reportInvalidReference(String reference, Info info)
{
LOGGER.info("REFRERENCE: " + reference + " Info <" + info + ">");
}
}
You'll also need to add the following to your velocity.properties file:
eventhandler.invalidreferences.class=path.to.package.AppSpecificInvalidReferenceEventHandler,org.apache.velocity.app.event.implement.ReportInvalidReferences
You might be surprised at the results though, so it will likely need fine-tuning dependent upon your needs.
I'm basing this off of Engine-1.7 code.
It seems that when an invalid method is called that the utility method EventHandlerUtil.invalidGetMethod is called. This method creates a new InvalidGetMethodExecutor (this is an inner class on InvalidReferenceEventHandler). Eventually this chains down into a call to invalidReferenceHandlerCall which eventually iterates over any handlerIterators which have been defined. Unfortunately I don't know enough about the internals of Velocity to tell you how to inject these values though. My guess is that the user list will suggest a way to override this behavior or a suggestion will be to use / implement a custom tool.
Edit:
According to the Developer Guide you can do the following. You'll need to write some code to deal with it, but it shouldn't be too difficult:
Pluggable Introspection
runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl
This property sets the 'Uberspector', the introspection package that handles all introspection strategies for Velocity. You can specify a comma-separated list of Uberspector classes, in which case all Uberspectors are chained. The default chaining behaviour is to return the first non-null value for each introspection call among all provided uberspectors. You can modify this behaviour (for instance to restrict access to some methods) by subclassing org.apache.velocity.util.introspection.AbstractChainableUberspector (or implementing directly org.apache.velocity.util.introspection.ChainableUberspector). This allows you to create more interesting rules or patterns for Uberspection, rather than just returning the first non-null value.

LinQ to SQL and CLR User Defined Types

I have created a User Defined Type in .Net 3.5 as per my blog entry at :
http://jwsadlerdesign.blogspot.com/2009/04/this-is-how-you-register.html
This works fine when using SQL with technologies like nHibernate.
However, when I try to map my LinQ to SQL class to use this UDT (with attribute defintions not XML), and I setup the property as the enumeration. I cannot get LinQ to map to this type. I have tried Image, Binary, varchar and integer all of which seem to issue Invalid Cast errors.
In particular I get the error 'Unable to cast object of type 'ISTD.InstallManager.Common.Classes.SQLUDTTargetType' to type 'System.Byte[]' any ideas or help would be much appreciated.
James.
UPDATE: I ran into this myself recently and found that the previous solution wasn't quite complete. Despite what all of the documentation says, it is possible to do this, but somewhat painful.
The first step, for your own convenience, is to implement some conversion operators:
public class MyUDT : INullable, IBinarySerialize
{
// Class implementation would go here
// ...
public static explicit operator MyUDT(byte[] data)
{
using (MemoryStream stream = new MemoryStream(data))
{
using (BinaryReader reader = new BinaryReader(stream))
{
MyUDT result = new MyUDT();
result.Read(reader);
return result;
}
}
}
public static explicit operator byte[](MyUDT x)
{
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(ms))
{
x.Write(writer);
}
return ms.ToArray();
}
}
}
Linq to SQL will still flat-out refuse to give you the UDT field, no matter how you declare the property. So you have to give it a binary field instead. You don't need a stored procedure or any custom SQL for this, just add a computed column to your table:
ALTER TABLE MyTable
ADD UDTField_Data AS CAST(UDTField AS varbinary(len))
Where len is whatever your UDT defines in the MaxByteSize attribute.
Now you can finally get access to the column data. You might be tempted to use your UDT as the return type of the new property, thinking that Linq to SQL will find your conversion operator and automatically convert from the byte array; don't bother. Linq to SQL will decide that it's actually a serialized .NET object and spit out a message to the effect of "input stream is not a valid binary format." Instead, you need another layer of indirection:
private MyUDT udtField;
[Column(Name = "UDTField_Data", DbType = "varbinary(len)")]
private byte[] UdtFieldData
{
get { return (byte[])udtField; }
set { udtField = (MyUDT)value; }
}
public MyUDT UdtProperty
{
get { return udtField; }
set { udtField = value; }
}
A few notes to make it clear what's going on here:
The actual field data (udtField) is declared as the UDT itself, not a byte array. The reason for this is that we only want the conversion to happen when loading from or saving to the database. If you had to convert the byte array to the UDT every time you accessed it, it would not only hurt performance, but it would cause inconsistencies if the UDT declares any mutable fields.
The raw byte[] property (UdtFieldData) is declared private, so consumers only see the UDT itself. Linq to SQL will still read it as long as it has the [Column] attribute.
The UdtFieldData property does not declare a storage property. This is critical; if you try to use the UDT field as the storage property, you'll just get the same type conversion error.
Finally, the UdtProperty property is how consumers actually get to access the data. To them it looks like any other property.
It's unfortunate that you have to jump through so many hoops to get this to work, but it does work. You'll probably have difficulties doing this kind of massaging through the Linq surface designer, which is just one of several reasons why I don't use it; better to write the classes yourself and use SqlMetal to help you along if necessary.

Recommendations on how to implement a validation class?

I am implementing a validation class in classic ASP. How should the validation class interface with my other classes?
My current setup:
The User class's set methods call the appropriate validation method in the validation class. Any errors that occur are stored in User.mError. For example, here's my set method for the Email member variable in ASP Classic:
Class User
Property Let Email(EmailInput)
If (myValidation.isEmail(EmailInput)) then
mEmail = EmailInput
Else
mError = "Invalid Email Address format."
End If
I don't like how I'm going to need an error member variable for every object that calls my validation class. Suggestions on a better setup?
Any suggestions for a validation architecture I should review as a benchmark?
You should try the validation concept used in ajaxed (which is an AJAX library for classic ASP - www.webdevbros.net/ajaxed/). Unfortunately the validator will be officialy released in version 2.0 but its already available in SVN - you could easily use it without the whole library (standalone)
Ajaxed has a class called validator which you can use to validate your business objects. It requires the creation of an isValid() method which takes a Validator as an argument and returns if the instance is valid or not. The isValid() method is called before saving the instance. It performs all validations and fills the given validator if anything is invalid.
Example:
class User
public firstname
public lastname
'validates the user instance
'- call before save()
public function isValid(byRef v)
isValid = true
if len(firstname) < 5 then
v.add "firstname", "Firstname must be at least 5 chars long."
isValid = false
end if
if len(lastname) < 5 then
v.add "lastname", "Lastname must be at least 5 chars long."
isValid = false
end if
end function
public sub save()
'do some DB stuff
end sub
end class
'usage scenario 1 (simple - we just know if valid or not)
set u = new User
if u.isValid(new Validator) then
u.save()
else
response.write("User is invalid. some error happend")
end if
'usage scenario 2 (detailed - we have an error summary)
set u = new User
u.firstname = "Michal"
set v = new Validator
if u.isValid(v) then
u.save()
else
'the validator offers a helper to create a validation summary
response.write(v.getErrorSummary("<div><ul>", "<ul/></div>", "<li>", "</li>"))
end if
'usage scenario 3 (we can even validator more users in one go)
set u1 = new User
set u2 = new User
set v = new Validator
u1.isValid(v)
u2.isValid(v)
if v then
u1.save()
u2.save()
else
response.write("something is invalid")
end if
I am using this aproach for years already and its very flexible. You can use the Validator class as standalone but I would recommend you use the ajaxed library as a whole. It lets you develop ASP more easier.
I would suggest looking at Validator related classes provided by .net framework.
In your case, you can have a Validator Class (EmailValidator to be specific), which could have a method named Validate which takes a string, returns a boolean
You could also pass ErrorMessage as one of the parameters of the Validate function
e.g.
Psuedo Code.
class EmailValidator
...
function Validate(byval EmailAddress as string, optional byval Result as string) as boolean)
..
if (condition success)
result = success
elseif (emailafddress doesnt have #)
result = "invalid email address. missing #"
endif
end function
end class
You can take error message out, if you want to have control over it.
I invite fellow SO guys to suggest any shortcomings in this.
Spring has its own validator pattern for validating sophisticated objects and returning multiple errors. It's detailed here.
I have written my own Validator class a few different ways. Validation in nature doesn't necessarily require an instantiated object, so I created a class with static methods to do validation. I have used one validator method where you have to pass a type in (e.g. Email, First Name, website...), or multiple methods each for the given types. In the end, there is really only one algorithm that I needed, so I went with the one method approach. Essentially, there are class properties to hold your validation regular expressions for each type, as well as an associated error message for the given type. It all equates to a class similar to the one below:
class Validation
{
// define the properties for dealing with different type validations
public static $firstNamePattern = '/[-a-zA-Z0-9._ ]{2,}/';
public static $lastNamePattern = '/[-a-zA-Z0-9._ ]{2,}/';
// ... more fields
public static function validateText($type, $text, $fieldName)
{
$pattern = $type."Pattern";
if ($this->$pattern != '')
{
// perfom the validation
// ...
return true; // or false
}
}
// other validation methods below
// ...
}
Then you can call that method from anywhere you need to (e.g. while validating form input).
if (Validation->validateText('firstName', $formFirstName, 'First Name'))
{
// validation passed
}
else
{
// validation failed
}
I apologize the above is written in PHP and the question was about ASP, but you get my drift.