|
User-8621695 wrote: will that memory get de-allocated after completion of unit test? Yes, since the scope of the variables is restricted to the test methods, they will be deallocated on return from the method.
|
|
|
|
|
Something you need to consider when you put strings in place using syntax like string s1 = "1,2"; or myClass.CallMethod("3,4"); ; these strings are interned in the string pool. In other words, the string is not garbage collected until the tests finish and the AppDomain is unloaded.
|
|
|
|
|
In terms of memory management they are the same. When you inline a string it still creates a string object which is stored in memory, the only difference is that it isn't assigned to a variable. Same with the int. In terms of performance, if you are in debug mode then you could argue the first version will perform worse due to the variable allocations, but we're talking single cpu cycles of difference. In release mode both of those code samples will effectively compile to the same code as the optimiser will inline the variables for you.
As for when they are deallocated, a test method is no different from any other method so the variables will be handled like normal.
|
|
|
|
|
the .NET String class is a reference type, correct?
Why then must I add the ref keyword to a string argument if I want its value to be updated in the called function?
No other reference type behaves this way, correct?
UPDATE: I just realized what's going on. Strings are immutable so when you pass a string with the ref keyword, it's the original reference to the string that is being updated with the new string. Without the ref keyword, the called function gets its own reference to the string, and if changes are made, then it's the function's reference that is updated, not the original reference.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Dat's de bunny!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I look at 'string as a chimera: a reference type (heap allocated [1], a class, no fixed allocation size, can be 'null) with value type semantics (immutability). Adding to the inter-species flavor is that == will compare content, not references. Under the hood a Char[].
[1] Eric Lippert's blogs illuminate the complexity of strings and memory allocation in .NET:Quote: "It is simply false that the choice of whether to use the stack or the heap has anything fundamentally to do with the type of the thing being stored. The truth is: the choice of allocation mechanism has to do only with the known required lifetime of the storage."
[^]
[^]
you'll have to look for these since @@^77!! MSDN has archived them:
http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation- detail.aspx
http://blogs.msdn.com/b/ericlippert/archive/2009/05/04/the-stack-is-an-implementation- detail-part-two.aspx
http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
modified 31-Mar-20 23:25pm.
|
|
|
|
|
Thanks Bill! That's a very useful post.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
here's a Lippert blog I find very relevant: Strings, immutability and persistence[^]
i like to confuse my students by asking them: if a Point is a ValueType (immutable), why can you set its X/Y properties directly without creating a new copy. To (maybe) get across the idea that immutable and passed by value are not necessarily synonymous.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
Richard Andrew x64 wrote: the .NET String class is a reference type, correct?
No, it's a value type. Even though strings are heap-based, .net does smoke-and-mirrors behind the scenes to ensure strings behave like value types. Probably to make the language easier to use as strings are very common. The downside is that it can lead to poor performance if you're not aware of the caveats.
|
|
|
|
|
F-ES Sitecore wrote: No, it's a value type.
No, it's an immutable reference type. There's not much in the way of smoke-and-mirrors involved; you can easily create your own immutable reference type to get the same behaviour.
If string was really a value type, you wouldn't sensibly be able to have a value type with a string member. The entire string would be stored "in-line" within that struct, and you'd end up with stack overflow exceptions everywhere.
It's probably better to say that in some circumstances it's easier to think of string as a value type, even though it isn't.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: it's easier to think of string as a value type, even though it isn't
Which is what I was saying.
|
|
|
|
|
I have the following methods:
public int MyMethod<T>(IEnumerable<T> data)...
public int MyMethod<T>(T data)...
When I call MyMethod with a collection, it always executes the (T data) version. I understand why, but the only way I know of to fix it is to add a dummy parameter to the method prototype so the two overloads are different.
Is there a way to fix it so that I don't have to add the dummy parameter?
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Not that I know of - although you can add constraints to a generic method, there is no way to say "where T : !IEnumerable" unfortunatly.
You could check the type in a single method and route it to one of two private methods?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
OriginalGriff wrote: You could check the type in a single method and route it to one of two private methods?
I tried that, and it didn't want to work.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Strange - it works for me:
public void DoSomething()
{
MyClass m = new MyClass();
List<MyClass> list = new List<MyClass>() { m };
Console.WriteLine($"{ProcessDepending(list)}, {ProcessDepending(m)}");
}
public int ProcessDepending<T>(T instance)
{
if (instance is System.Collections.IEnumerable collection)
{
return ProcessCollection(collection);
}
return ProcessInstance(instance);
}
private int ProcessInstance<T>(T instance)
{
return 1;
}
private int ProcessCollection(IEnumerable collection)
{
return 2;
}
private class MyClass { }
I get 2, 1 as I expected.
The only thing I can't figure out is a way to get the collection in a form that I can define this:
private int ProcessCollection<T>(IEnumerable<T> collection) Because I can't get at the type of the collection objects at compile time ...
I can do this though:
public int ProcessDepending<T>(T instance)
{
if (instance is IEnumerable<object> collection)
{
return ProcessCollection<object>(collection);
}
return ProcessInstance(instance);
}
private int ProcessCollection<T>(IEnumerable<T> collection)
{
return 2;
}
And it'll work. Messy ...
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Yeah, I came with all that too, but since I had to create a new method anyway, I decided not to do that.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
this works using one overload in .NET 4.8; don't know about earlier releases:
private IEnumerable<T> DoSomething<T>(
Func<T,T> func,
params T[] args)
{
foreach (T t in args)
{
yield return func(t);
}
}
private IEnumerable<T> DoSomething<T>(
Func<T,T> func,
IEnumerable<T> args)
{
return DoSomething(func, args.ToArray());
}
I don't claim it's elegant
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
Point of order - I'm not returning a collection of generics, so it can't pick the appropriate overload.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
#realJSOP wrote: I'm not returning a collection of generics, so it can't pick the appropriate overload. Look again: this solution works: it's on you to adapt it to your specific needs.
Of course, I am assuming your choice of using the same method name (overloading) is rational, and that it implies one instance of T is handled the same way as multiple instances.
See my reply to Deeming, here.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
If you call MyMethod with something that has a compile-time type of IEnumerable<T> , you'll call the correct method.
If you call it with something where the compile-time type implements IEnumerable<T> , you'll call the wrong method.
MyMethod(Enumerable.Range(1, 42));
MyMethod(new[] { 1, 2, 3 });
MyMethod(new List<int> { 1, 2, 3 });
One workaround might be to add .AsEnumerable() to the method argument.
MyMethod(Enumerable.Range(1, 42));
MyMethod((new[] { 1, 2, 3 }).AsEnumerable());
MyMethod((new List<int> { 1, 2, 3 }).AsEnumerable());
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi Richard, using these tests with the code I posted here, I believe 'AsEnumerable may not be necessary:
var t0 = DoSomething(
t => t * 3,
100).ToList();
var t1 = DoSomething(
t => t * 3,
1,2,3,4,5).ToList();
var t2 = DoSomething(
t => t * 3, Enumerable.Range(6, 10)).ToList();
var t3 = DoSomething(
t => t * 3, new[] { 11, 12, 13 }).ToList();
var t4 = DoSomething(
t => t * 3, new List<int> { 14, 15, 16 }).ToList(); Of course, I am assuming J's choice of using the same method name (overloading) is rational, and that it implies one instance of T is handled the same way as multiple instances.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
If you start with the methods from John's post, you'll see the issue:
public static void Foo<T>(T value) => Console.WriteLine("Foo a single value");
public static void Foo<T>(IEnumerable<T> values) => Console.WriteLine("Foo multiple values");
public static void Bar()
{
Foo(42);
Foo(Enumerable.Range(1, 42));
Foo(new[] { 1, 2, 3 });
Foo(new List<int> { 1, 2, 3 });
Foo((new[] { 1, 2, 3 }).AsEnumerable());
Foo((new List<int> { 1, 2, 3 }).AsEnumerable());
} Generic Overload Resolution | C# Online Compiler | .NET Fiddle[^]
The question was, given an x whose compile-time type implements IEnumerable<> , is there a way to make Foo(x) call Foo(IEnumerable<T>) instead of Foo(T) , without modifying the call-site.
The answer seems to be that there isn't. If the compile-time type of x is not exactly equal to IEnumerable<> , then the compiler prefers to call the single-value method, using the compile-time type as the type parameter, rather than casting to IEnumerable<T> and calling the multi-value method.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi Richard, Maybe the 103F+ days, and air pollution over-the-toxic-top, and "sheltering in place," and ... gosh: old age ? ... are creeping up on me , so I am denser than usual, but ...
doesn't the code I posted (and the tests) demonstrate a working solution with only one overload to the issue here ?
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
<crickets>
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
|