var a;
...
...
if(a is t1){
t1 t=a as t1;
t.callSomething();
}
this code is so bulky, so is there a shorter version to call “callSomething” if a is t1
var a;
...
...
if(a is t1){
t1 t=a as t1;
t.callSomething();
}
this code is so bulky, so is there a shorter version to call “callSomething” if a is t1
You can marginally shorten that by removing the “is”, since the “as” will simply return null if the conversion is unsafe:
var a;
...
...
t1 t = (a as t1);
if (t != null) t.callSomething();
One could also wrap all of that in a helper function.
If you need to do this on a regular basis, though, it might be time to rethink how you’re using polymorphism.
Sometimes it’s appropriate to move that function into the base class with a default implementation that does nothing. For instance, maybe you need a “perform all nightly maintenance” function, but some subtypes don’t have any maintenance to perform; it might make more sense to implement the function on all types (with some of them doing nothing when called) rather than require the caller to explicitly check the subtype every night before starting maintenance.
Or maybe whatever thing the caller is doing should itself be turned into a method on the object, so that it will implicitly have all necessary information about the object while doing that thing.
You also have the ?. operator.
(variable as Type)?.Function();
You generally shouldn’t use ?. on any Unity type (including anything derived from MonoBehaviour) because of the weird pretend-null stuff Unity does.
If the type in question is unrelated to Unity and your project is set to use a sufficiently-recent .NET version, then sure.
ty that was what I was looking for
With C# 7 you can do this:
if(a is t1 t)
{
t.callSomething();
}
Heed Antistone’s warning, or you’ll pay the price (usually half your hair per week).
Also - and I know that it’s a pet peeve of mine - I firmly believe that what you call ‘bulky’ code simply is clear code. You are doing something that is non-Standard, so the code should carefully explain what you are doing. Casting a pointer should always be self-elaborating in code. The compiler will NOT genereate more code if you use additional statements for clarity, the optimizer will take care of that. So if you ever plan to revisit your code later, be greatful if your casting is as Elaborate as possible.
Yes, IMHO. But that’s all I have
C Sharp supports Extension Methods (C# Programming Guide). You could write an extension method for your type of a and as a result then simply write:
a.CallSomething()
with CallSomething() being an extension method on your type a, handling the conversion to type of t1. If this is a good approach is debatable, but it would be one of the shortest solutions.
Pseudo-Code for the extension method could look like this:
public static class MyExtensions
{
public static void CallSomething(this TypeA a)
{
if(a is TypeOne t) t.CallSomething();
}
}
hmm I read it, but I’m not quite sure if I understand it right. Unity overrides the “==” of GameObjects, so a destroyed Object appears to be null even if it isn’t really null. But in this particular case it shouldn’t be a problem since I’m not going to call the method anyways if the object is supposed to be destroyed. Or am I missing something?
Well, I guess this should be clear enough:
When speaking of Monobehaviour:
“This class doesn’t support the null-conditional operator (?.) and the null-coalescing operator (??).”
@csofranz @Antistone I’ll keep it in mind
I may be just ignorant about something here, but for which usecase is this required?
I’ve personally never really used var and never missed it. To me it’s mostly a “lazy prototyping tool”. Thus i dont think that there is any situation in which it is required, which implies you could prevent the “bulky code” by simply not using var and instead doing it “properly” in the first place. But i’m curious if i’m missing something here.
It’s good for particularly lengthy data types:
Dictionary<string, List<Vector3>> someLongList = new Dictionary<string, List<Vector3>>();
//add stuff
foreach (KeyValuePair<string, List<Vector3>> kvp in someLongList) {
Is a little absurd both to type and to read, let alone refactor. But:
var someLongList = new Dictionary<string, List<Vector3>>();
//add stuff
foreach (var kvp in someLongList) {
No no no no no no no no no noooooooo!!
@StarManta noted a place where it is convenient.
But I can think of a place it’s required. And that is when you are dealing with anonymous types. You don’t know the type (it’s generated at runtime), so you can’t declare the type when declaring the variable, therefore you must use var.
Of course anonymous types aren’t required either, but if you use them, then you’re required to use var if you expect to have a variable that stores them (without downcasting to object, or using dynamic).
And personally I like var for the very reason StarManta suggested. It can make code more readable. It could be argued there are use cases that are less readable, and I would avoid those specific cases of using var. That’s basically my case by case taste of it… if it makes my line of code more confusing, I won’t do it.
This of course could be said of explicit typing as well… it can be more readable in some cases, and less in others. Saying int i = 0, vs var i = 0, var is more confusing. But saying StarManta’s scenario, the explicit type is more confusing. So the fact var can cause less readability in edge cases isn’t an argument against it, since the same can be said of explicit typing.
I’d compare it to a ‘contraction’ in English. It’s useful for shortening a phrase, at the expense of sometimes being confusing if it becomes a homophone to another word in the sentence. So in most cases it’s a great shorthand, and you only avoid it in those edge cases. But if you don’t want to use it, well have at it… say all the ‘can not’ ‘are not’ and 'did not’s that you want.
I see the convenience in the foreach loop, even tho personally i would prefer the longer type declaration. I guess this is rather subjective anyways, since it’s optional to use.
Still optional overall, as you said, but sure that’s a scenario in which they definitely are useful.
Thanks for the clarifications at both of you. I guess i personally just prefer knowing all the types directly, and making heavy use of var can result in longer lookup times for what type exactly you are looking at. It may just be that i dont like var since i used to work with somebody who abused the living sh*t out of it (other language tho) and his code was really confusing to read and work with. However, for some infrequent cases i guess it is a convenience to improve readability
Mind you that var works very different in C# than it may in other languages.
I’m not sure which language you’re referring to, but if it’s per chance ‘javascript’, they behave way different. ‘var’ in javascript behaves more like ‘dynamic’ in C#.
‘var’ in C# requires that the compiler should be able to infer the data type from context.
For example:
var dict = new Dictionary<string, int>();
We can easily infer what dict is because the variable is being declared and set to a Dictionary<string, int>, clearly it’s a Dictionary<string, int>.
Where as:
var obj = null;
This is invalid, we can’t infer what ‘obj’ is going to be since so many types could potentially be set to null. The compiler, nor ourselves reading it, can infer what the type is. And therefore this wont’ compile.
Effectively, when a ‘var’ variable is declared, something immediately following it (usually an assignment) will infer its type. Otherwise compiler complains.
The one place where I can see this getting confusing is when accessing members of another object, like enumerables, or properties:
foreach(var obj in someList)
var obj = someReference.someProperty;
Here we must know what type someList is, or someProperty is, to infer what obj is. The compiler can infer it easily, but readability wise you may not. And here is where your naming conventions of variables play a very important role… or you just avoid the ‘var’ in the cases where the naming convention sucks (say you can’t control it, like the property of a class coming from some 3rd party library).
For example, lets consider these:
var go = collider.gameObject;
byte[] byteData = someObj.data;
The first one is obvious that gameObject is of type GameObject, so the use of 'var is not confusing.
But the 2nd, data could be anything, so I’ve explicitly typed it to what it is, and gave it a better name for my local scope.
for example:
public void doSomething(object o){
if(o is type1){
//do something
}
else if(o is type2){
//do something else
}
}
Absolutely not required. Besides the fact that var does not change anything about the strongly typed system, it can be very beneficial for overall readability and aesthetics, but that’s subjective.
Perhaps you’ll start to like it once you’ve used it. Some years ago I thought the same, I had the same mindset and never thought this would ever be useful for me, why would I want to omit type information… silly language devs rolling eyes… until I finally started to use it.
Soon it turned out it made me choose better identifiers.
Code looked much cleaner, no unnecessarily long types in front of the actual identifiers.
And then, there are multiple lines of variable declarations… No difference in type length, lines start with the same textual pattern, incredibly satisfying, easier to read. Still subjective, but I don’t wanna miss it.
This would only make sense if you don’t have (or aren’t allowed to modify) the source code for the actual classes in question. If you can modify the class, then adding the function to the base type makes more sense than creating an extension method that checks for the subtype, because then you can take advantage of built-in polymorphism features instead of using the relatively-expensive conditional casting, plus it’ll be easier to extend for any new subtypes you create.
Note that while the OP happened to use “var” in the example, the original question has absolutely nothing to do with “var”. The example could just as easily have been:
BaseClass a;
...
...
if (a is SubClass)
{
SubClass b = a as SubClass;
b.callSomething();
}