Using Familiar Command Names in Windows PowerShell
Using a mechanism called aliasing, Windows PowerShell allows users to refer to commands by alternate names. Aliasing allows users with experience in other shells to reuse common command names that they already know to perform similar operations in Windows PowerShell. Although we will not discuss Windows PowerShell aliases in detail, you can still use them as you get started with Windows PowerShell.
Aliasing associates a command name that you type with another command. For example, Windows PowerShell has an internal function named Clear-Host that clears the output window. If you type either the cls or clear command at a command prompt, Windows PowerShell interprets that this is an alias for the Clear-Host function and runs the Clear-Host function.
This feature helps users to learn Windows PowerShell. First, most Cmd.exe and UNIX users have a large repertoire of commands that users already know by name, and although the Windows PowerShell equivalents may not produce identical results, they are close enough in form that users can use them to do work without having to first memorize the Windows PowerShell names. Second, the major source of frustration in learning a new shell when the user is already familiar with another shell, is the errors that are caused by "finger memory". If you have used Cmd.exe for years, when you have a screen full of output and want to clean it up, you would reflexively type the cls command and press the ENTER key. Without the alias to the Clear-Host function in Windows PowerShell, you would simply get the error message "'cls' is not recognized as a cmdlet, function, operable program, or script file." and be left with no idea of what to do to clear the output.
The following is a brief listing of the common Cmd.exe and UNIX commands that you can use inside Windows PowerShell:
| cat | dir | mount | rm |
| cd | echo | move | rmdir |
| chdir | erase | popd | sleep |
| clear | h | ps | sort |
| cls | history | pushd | tee |
| copy | kill | pwd | type |
| del | lp | r | write |
| diff | ls | ren |
If you find yourself using one of these commands reflexively and want to learn the real name of the native Windows PowerShell command, you can use the Get-Alias command:
| PS> Get-Alias cls CommandType Name Definition ----------- ---- ---------- Alias cls Clear-Host |
To make examples more readable, the Windows PowerShell Primer generally avoids using aliases. However, knowing more about aliases this early can still be useful if you are working with arbitrary snippets of Windows PowerShell code from another source or wish to define your own aliases. The rest of this section will discuss standard aliases and how to define your own aliases.
Interpreting Standard Aliases
Unlike the aliases described above, which were designed for name-compatibility with other interfaces, the aliases built into Windows PowerShell are generally designed for brevity. These shorter names can be typed quickly, but are impossible to read if you do not know what they refer to.
Windows PowerShell tries to compromise between clarity and brevity by providing a set of standard aliases that are based on shorthand names for common verbs and nouns. This allows a core set of aliases for common cmdlets that are readable once you know the shorthand names. For example, in standard aliases the verb Get is abbreviated to g, the verb Set is abbreviated to s, the noun Item is abbreviated to i, the noun Location is abbreviated to l, and the noun Command is abbreviated to cm.
Here is a brief example to illustrate how this works. The standard alias for Get-Item comes from combining g for Get and i for Item: gi. The standard alias for Set-Item comes from combining s for Set and i for Item: si. The standard alias for Get-Location comes from combining g for Get and l for Location, gl. The standard alias for Set-Location comes from combining s for Set and l for Location, sl. The standard alias for Get-Command comes from combining g for Get and cm for Command, gcm. There is no Set-Command cmdlet, but if there were, we would be able to guess that the standard alias comes from s for Set and cm for Command: scm. Furthermore, people familiar with Windows PowerShell aliasing who encounter scm would be able to guess that the alias refers to Set-Command.
Creating New Aliases
You can create your own aliases using the Set-Alias cmdlet. For example, the following statements create the standard cmdlet aliases discussed in Interpreting Standard Aliases:
| Set-Alias -Name gi -Value Get-Item Set-Alias -Name si -Value Set-Item Set-Alias -Name gl -Value Get-Location Set-Alias -Name sl -Value Set-Location Set-Alias -Name gcm -Value Get-Command |
Internally, Windows PowerShell uses commands like these during startup, but these aliases are not changeable. If you attempt to actually execute one of these commands, you will get an error explaining that the alias cannot be modified. For example:
PS> Set-Alias -Name gi -Value Get-Item
Set-Alias : Alias is not writeable because alias gi is read-only or constant and cannot be written to.
At line:1 char:10
+ Set-Alias <<<< -Name gi -Value Get-Item
Posted in: MS Windows| Tags: Windows CLS PowerShell Cmdlets Windows PowerShell Syntax mechanism Aliasing cat cd dir mount rm move echo sleep popd erase clear copy kill pwd type tee sort ren ls del diff pushd write Clear-HostPrefer CLS-Compliant Assemblies
The .NET environment is language agnostic: Developers can incorporate components written in different .NET languages without limitations. In practice, it's almost true. You must create assemblies that are compliant with the Common Language Subsystem (CLS) to guarantee that developers writing programs in other languages can use your components.
CLS compliance is a new twist on that least common denominator approach to interoperability. The CLS specification is a subset of operations that every language must support. To create a CLS-compliant assembly, you must create an assembly whose public interface is limited to those features in the CLS specification. Then any language supporting the CLS specification must be capable of using the component. This does not mean you must limit your entire programming palette to the CLS-compliant subset of the C# language, however.
To create a CLS-compliant assembly, you must follow two rules. First, the type of all parameters and return values from public and protected members must be CLS compliant. Second, any non-CLS-compliant public or protected member must have a CLS-compliant synonym.
The first rule is simple to follow: You can have it enforced by the compiler. Add the CLSCompliant attribute to your assembly:
[ assembly: CLSCompliant( true ) ]
The compiler enforces CLS compliance for the entire assembly. If you write a public method or property that uses a construct that is not compliant with CLS, it's an error. That's good because it makes CLS compliance an easy goal. After turning on CLS compliance, these two definitions won't compile because unsigned integers are not compliant with CLS:
// Not CLS Compliant, returns unsigned int:
public UInt32 Foo( )
{
return _foo;
}
// Not CLS compliant, parameter is an unsigned int.
public void Foo2( UInt32 parm )
{
} Remember that creating a CLS-compliant assembly affects only items that can be seen outside of the current assembly. Foo and Foo2 generate CLS compliance errors when declared either public or protected. However, if Foo and Foo2 were internal, or private, they could be included in a CLS-compliant assembly; CLS-compliant interfaces are required only for items that are exposed outside the assembly.
What about this property? Is it CLS compliant?
public MyClass TheProperty
{
get { return _myClassVar; }
set { _myClassVar = value; }
} It depends. If MyClass is CLS compliant and indicates that it is CLS compliant, this property is CLS compliant. On the other hand, if MyClass is not marked as CLS compliant, this property is not CLS compliant. That means that the earlier TheProperty is CLS compliant only if MyClass resides in a CLS-compliant assembly.
You cannot build a CLS-compliant assembly if you have types in your public or protected interface that are not CLS compliant. If, as a component designer, you do not have an assembly marked as CLS compliant, you make it harder for users of your component to create CLS-compliant assemblies. They must hide your types and mirror the functionality in a CLS-compliant wrapper. Yes, this can be done. But, no, it's not a good way to treat the programmers who want to use your components. It's better to strive for CLS-compliant assemblies in all your work: This is the easiest way for clients to incorporate your work in their CLS-compliant assemblies.
The second rule is up to you: You need to make sure that you provide a language-agnostic way to perform all public and protected operations. You also need to make sure that you do not sneak a noncompliant object through your interface using polymorphism.
Operator overloading is a feature that some love and others hate. As such, not every language supports or allows operator overloading. The CLS standard does not take a pro or con stance on the concept of operator overloading. Instead, it defines a function name for each operator: op_equals is the function name created when you write an operator = function. op_addis the name for an overloaded addition operator. When you write an overloaded operator, the operator syntax can be used in languages that support overloaded operators. Developers using a language that does not support operator overloading must use the op_ function name. If you expect these programmers to use your CLS-compliant assembly, you should provide a more convenient syntax. That leads to this simple recommendation: Anytime you overload an operator, create a semantically equivalent function:
// Overloaded Addition operator, preferred C# syntax:
public static Foo operator+( Foo left, Foo right)
{
// Use the same implementation as the Add method:
return Foo.Add( left, right );
}
// Static function, desirable for some languages:
public static Foo Add( Foo left, Foo right)
{
return new Foo ( left.Bar + right.Bar );
} Finally, watch out for non-CLS types sneaking into an interface when you use polymorphic arguments. It's easy to do with event arguments. You can create a type that is not compliant with CLS and use it where a base type that is CLS-compliant is expected.
Suppose that you created this class derived from EventArgs:
internal class BadEventArgs : EventArgs
{
internal UInt32 ErrorCode;
} The BadEventArgs type is not CLS compliant; you should not use it with event handlers written in other languages. But polymorphism makes this easy to do. You can declare the event type to use the base class, EventArgs:
// Hiding the non-compliant event argument: public delegate void MyEventHandler( object sender, EventArgs args ); public event MyEventHandler OnStuffHappens; // Code to raise Event: BadEventArgs arg = new BadEventArgs( ); arg.ErrorCode = 24; // Interface is legal, runtime type is not: OnStuffHappens( this, arg );
The interface declaration, which uses an EventArgs argument, is CLS compliant. However, the actual type you substituted in the event arguments was not. The end result is a type that some languages cannot use.
This discussion of CLS compliance ends with how CLS-compliant classes implement compliant or noncompliant interfaces. It can get complicated, but we'll simplify it. Understanding CLS compliance with interfaces also will help you fully understand what it means to be CLS compliant and how the environment views compliance.
This interface is CLS compliant if it is declared in a CLS-compliant assembly:
[ assembly:CLSCompliant( true ) ]
public interface IFoo
{
void DoStuff( Int32 arg1, string arg2 );
} You can implement that interface in any CLS-compliant class. However, if you declare this interface in an assembly that is not marked as CLS compliant, the IFoo interface is not CLS compliant. In other words, an interface is CLS compliant only if it is defined in a CLS-compliant assembly; conforming to the CLS spec is not enough. The reason is compiler performance. The compilers check CLS compliance on types only when the assembly being compiled is marked as CLS compliant. Similarly, the compilers assume that types declared in assemblies that are not CLS compliant actually are not CLS compliant. However, the members of this interface have CLS-compliant signatures. Even if IFoo is not marked as CLS compliant, you can implement IFoo in a CLS-compliant class. Clients of this class could access DoStuff tHRough the class reference, but not through the IFoo reference.
Consider this small variation:
public interface IFoo2
{
// Non-CLS compliant, Unsigned int
void DoStuff( UInt32 arg1, string arg2 );
} A class that publicly implements IFoo2 is not CLS compliant. To make a CLS-compliant class that implements IFoo2, you must use explicit interface implementation:
public class MyClass: IFoo2
{
// explicit interface implementation.
// DoStuff() is not part of MyClass's public interface
void IFoo2.DoStuff( UInt32 arg1, string arg2 )
{
// content elided.
}
} MyClass has a CLS-compliant public interface. Clients expecting the IFoo2 interface must access it through the non-CLS-compliant IFoo2 pointer.
Complicated? No, not really. Creating a CLS-compliant type mandates that your public and protected interfaces contain only CLS-compliant types. It means that your base class must be CLS compliant. All interfaces that you implement publicly must be CLS compliant. If you implement a non-CLS compliant interface, you must hide it from your public interface using explicit interface implementation.
CLS compliance does not force you to adopt a least common denominator approach to your designs and implementations. It means carefully watching the publicly accessible interfaces of your assembly. For any public or protected class, any type mentioned in these constructs must be CLS compliant:
-
Base classes
-
Return values for public and protected methods and properties
-
Parameters for public and protected methods and indexers
-
Runtime event arguments
-
Public interfaces, declared or implemented
The compiler tries to enforce a compliant assembly. That makes it easy for you to provide some minimum level of CLS support. With a bit of extra care, you can create an assembly that anyone using any language can use. The CLS specification tries to ensure that language interoperability is possible without sacrificing the constructs in your favorite language. You just need to provide alternatives in the interface.
CLS compliance requires you to spend a little time thinking about the public interfaces from the standpoint of other languages. You don't need to restrict all your code to CLS-compliant constructs; just avoid the noncompliant constructs in the interface. The payback of interlanguage operability is worth the extra time.
Posted in: .NET Framework| Tags: .NET C# Assembly CLS CLS-Compliant