How to set args for a method? - c#

In my properties, I have several bools called Username, Frames, Time, and Rerecords. Also, there is a string called StringFormat. I will explain further in a moment.
I have an object called User with variables(is this the right word?) User.Username, User.Frames, User.Time, User.Rerecords. Each variable is a string, int, int, int respectively.
Finally, I have a method:
public void Display(string stringFormat, params object[] args)
{
// stringFormat = Properties.Settings.Default.Format
lbl_Display.Text = string.Format(stringFormat, args);
}
I wish uses the User variables as the args IF the property variables of the same names are True.
How can I do this? Currently, my research has lead me here, but it hasn't been of any help.
Any help would be greatly appreciated. Thank you.
Edit:
I did it with some spaghetti code, to simulate the response:
public void Display()
{
// spaghetti code - Fix later
NumberConverter nc = new NumberConverter();
List<bool> settings = new List<bool>
{
Properties.Settings.Default.Username,
Properties.Settings.Default.Frames,
Properties.Settings.Default.Time,
Properties.Settings.Default.Rerecords
};
List<string> args = new List<string> { };
if (settings[0])
args.Add(compList[listIndex].Username);
if (settings[1])
args.Add(compList[listIndex].Frames.ToString());
if (settings[2])
args.Add(nc.FormatTime(compList[listIndex].Frames));
if (settings[3])
args.Add(compList[listIndex].Rerecords.ToString());
lbl_Display.Text = string.Format(Properties.Settings.Default.Format, args.Cast<object>().ToArray());
}

Related

How to evaluate local variable/ parameter state with Roslyn

I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}

How to pass a dynamic pair of key/values to a function?

I've already read this an this, but this doesn't answer to my needs.
I'm learning Csharp and here's one of my first functions:
public void AskServer(string URL, WWWForm form)
{
WWWForm form = new WWWForm(URL);
form.AddField("step", StateManager.STEP_GET_CONF);
form.AddField("pseudo", this._pseudo);
form.AddField("jeton", this._dernierJeton.ToString());
/*... a bit more out of scope code...*/
}
I would like to do a (far more) generic stuff like this:
public void AskServer(string URL, ...)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(param[i], param[i+1]);
)
}
then call the function -somehow- like that:
AskServer("http://myweb", "pseudo", this._pseudo, "jeton", this._jeton);
Maybe if you have a nicer way of writing this, you are welcome, maybe something like in JavaScript:
AskServer("http://myweb", {
"pseudo": this._pseudo,
"jeton": this._jeton
});
One of my problems is that I need to pass value that may not be strings (key will always be).
The params keyword will let you specify a variable number of arguments (must be the last parameter). You can then treat that as an array.
public void AskServer(string url, params object[] args)
{
WWWForm form = new WWWForm(url);
for (int i = 0; i < args.GetLength(0); i++)
form.Addfield(args[i].ToString(), args[++i]);
}
Called as,
AskServer("http://myweb", "pseudo", 1, "jeton", 234);
Or as an alternative approach, use a list instead with strong type on the key (the generic declaration is ugly so you can alias it in namespaces)
using Kvp = System.Collections.Generic.KeyValuePair<string, object>;
....
public void AskServer(string url, List<Kvp> kvps)
{
WWWForm form = new WWWForm(url);
foreach (var arg in kvps)
form.Addfield(arg.Key, arg.Value);
}
Called as:
AskServer("http://myweb",
new List<Kvp>() {
new Kvp("pseudo", 1),
new Kvp("jeton", 234)
});
there are several ways to obtain this result.
parameter array, Tuple, anonymous types, ...
for example you can write
public void AskServer(string URL, params object[] values)
{
...
}
and pass as many parameters as you want
I would try this...
public void AskServer(string url, KeyValuePair<string, object>[] parameters)
{
WWWForm form = new WWWForm(URL);
/* do a loop on all parameters following the first one */
for (/*dont know how to write this*/) {
form.AddField(parameters[i].Key, parameters[i].Value);
)
}

null reference in coded webtest with system.datetime

I was very excited to try out the new feature in VS 2012 ultimate that allows you to run whole load tests with coded web tests.
Unfortunatly, I've ran into a bit of a problem. While trying to debug a web test I've generated (and edited afterwards), I keep getting an NullReferenceException on a simple declaration line. I simply cannot wrap my head around why this occurs. Here's the code:
[Priority(0)]
public class CreateSessionCoded : WebTest
{
public string[] SessionID;
public string[] SessionTime;
public string[] CreatedTime;
public CreateSessionCoded()
{
this.Context.Add("Parameter1", "");
this.PreAuthenticate = true;
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
//string CurrentITR = this.Context.WebTestIteration.ToString();
SessionID[this.Context.WebTestIteration] = Guid.NewGuid().ToString();
SessionTime[this.Context.WebTestIteration] = System.DateTime.UtcNow.ToString();
CreatedTime[this.Context.WebTestIteration] = System.DateTime.Now.ToString();
...
The code goes on, but the part where I get the NRE is at the last two lines where I try to assign values to my SessionTime and CreatedTime parameters.
It doesn't happen when assigning to the SessionID, so it's not about the WebTestIteration in any way. It also happens if I try to assign a different string (any casual string such as, say, "blabla") to the same parameters.
I'd really appreciate any help! Thanks in advance! :)
You define three arrays:
public string[] SessionID;
public string[] SessionTime;
public string[] CreatedTime;
But, they aren't initialized before you attempt to use them.
Basically, you are doing this:
string[] foo;
foo[1] = "bar";
And you need to do this:
string[] foo = new string[10]; // sized appropriately
foo[1] = "bar";

Using PrivateObject.Invoke to call a static conversion function do not compile in C#

I have a test method where I call an private function that converts a kind of to another kind.
This static function have the following signature:
private static Destiny[] Array2Array<Origin,Destiny> (Origin[] OriginVector)
Since it's a private function, the tester give an error saying it cannot access it. So I got to this point:
Origin[] OriginVector = null; // TODO: Initialize to an appropriate value
Destiny[] expected = null; // TODO: Initialize to an appropriate value
Destiny[] actual;
var dummy = new ConversionClass();
var po = new PrivateObject( dummy, new PrivateType(typeof(ConversionClass)));
var acessor = new ConversionClassAcessor(po);
actual = po.Invoke("Array2Array",
new [] { typeof(Origin[]), typeof(Destiny[]) },
new object[] { OriginVector } );
EDIT: That last line throws an compiler error with the message "cannot convert type object to Destiny[]". What I'm doing wrong?
The answer is simple.. cast it. :D
actual = (Destiny[]) po.Invoke("Array2Array",
new [] { typeof(Origin[]), typeof(Destiny[]) },
new object[] { OriginVector } );
Mr Chris Shain,
I will here reproduce the solution you gave me. Since you deleted your answer, if you add a new one after this, I'll delete this and accept yours as the question's answer.
The problem with the code above is that actual variable is of type Destiny[] and the result of Invoke is System.Object. An typecast is needed:
actual = (Destiny[]) po.Invoke("Array2Array",
new [] { typeof(Origin[]), typeof(Destiny[]) },
new object[] { OriginVector } );

How to call extension method "ElementAt"of List<T> with reflection?

I have problem that after creating object "oListType01" of type List < MyClass01 > and after assigning it to the another objet "oObjectType " of type "object" I can not access any more function "ElementAt(1)". I tried by using reflection but I am always getting exception(parameter conflict) in "Invoke" method. Does anyone knows why ?
Milan
MyClass01 oMy1 = new MyClass01();
oMy1._ID = "1";
MyClass01 oMy2 = new MyClass01();
oMy2._ID = "3";
IList<MyClass01> oListType01 = new List<MyClass01>();
oListType01.Add(oMy1);
oListType01.Add(oMy2);
object oObjectType = new object();
oObjectType = oListType01;
From here fowrads only object oObjectType is available (upwards happens in separate function call in the real case). In VS oObjectType shows two element which I would like to access per reflection.
MethodInfo mInfo = typeof(System.Linq.Enumerable).GetMethod("ElementAt").MakeGenericMethod(typeof(object));
object oSingleObject = mInfo.Invoke(oObjectType, new object[] { 1 });
I will assume you have a valid reason to be doing this but it seems a little wrong. That said here is some code that will accomplish what you are trying to do.
MethodInfo mInfo = typeof(System.Linq.Enumerable).GetMethod("ElementAt").MakeGenericMethod(typeof(MyClass01));
object oSingleObject = mInfo.Invoke(oObjectType, new object[] { oObjectType, 1 });
When I run this code I get the second element in the List.
The ElementAt extension method is probably on IEnumerable<T> and so when you treat your list like an object, the extension method won't be available unless you cast it. Either ((List<MyClass01>)oObjectType).ElementAt() or (oObjectType as List<MyClass01>).ElementAt().
I have to ask, though, with all due respect why you'd ever want to do this in the first place? It strikes me that there's something wrong here that could be done a little cleaner using interfaces.
If we can safely assume that:
oObjectType is a IEnumerable of some T
then here's the code to extract the items from it.
Note that I seriously wonder if this is the right way to go about this, but you haven't given us enough information to help you figure out if there's a better way, so all we're left with is just answering the question as asked.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
namespace ConsoleApplication2
{
class MyClass01
{
public String _ID;
public override string ToString()
{
return _ID;
}
}
class Program
{
static void Main(string[] args)
{
MyClass01 oMy1 = new MyClass01();
oMy1._ID = "1";
MyClass01 oMy2 = new MyClass01();
oMy2._ID = "3";
IList<MyClass01> oListType01 = new List<MyClass01>();
oListType01.Add(oMy1);
oListType01.Add(oMy2);
object oObjectType = new object();
oObjectType = oListType01;
Test(oObjectType);
Console.In.ReadLine();
}
private static void Test(object oObjectType)
{
Type tObject = oObjectType.GetType();
Debug.Assert(tObject.IsGenericType);
Debug.Assert(tObject.GetGenericArguments().Length == 1);
Type t = tObject.GetGenericArguments()[0];
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(t);
Debug.Assert(tIEnumerable.IsAssignableFrom(tObject));
MethodInfo mElementAt =
typeof(Enumerable)
.GetMethod("ElementAt")
.MakeGenericMethod(t);
Console.Out.WriteLine("o[0] = " +
mElementAt.Invoke(null, new Object[] { oObjectType, 0 }));
Console.Out.WriteLine("o[1] = " +
mElementAt.Invoke(null, new Object[] { oObjectType, 1 }));
}
}
}
This is really similar to your other question, but in this case, the static ElementAt method is actually requiring two parameters. Try this:
object oSingleObject = mInfo.Invoke(null, new object[] { oObjectType, 1 });

Categories

Resources