A XNamespace object can be created as below:
XNamespace ns="http://www.xyz.com";
Here the string "http://www.xyz.com" is interpreted as a property value(NamespaceName) of that class. I was wondering if I can create such a custom class where it can just be instantiated like that. The syntax actually looks pretty cool.
class MyClass
{
public string Value {get; private set;}
public MyClass(string s)
{
this.Value = s;
}
public static implicit operator MyClass(string s)
{
return new MyClass(s);
}
}
now you can:
MyClass myClass = "my string";
Console.WriteLine(myClass.Value); //prints "my string"
Note, that XNamespace also support addition operator, that accepts strings as right parameter. This is quite a good API decision, if you are dealing with strings. To implement this, you can overload addition operator as well:
//XNamespace returns XName (an instance of another type)
//but you can change it as you would like
public static MyClass operator +(MyClass val, string name)
{
return new MyClass(val.Value + name);
}
You just need to add an implicit conversion operator from string:
public class Foo
{
private readonly string value;
public Foo(string value)
{
this.value = value;
}
public static implicit operator Foo(string value)
{
return new Foo(value);
}
}
I'd use this with caution though - it makes it less immediately obvious what's going on when reading the code.
(LINQ to XML does all kinds of things which are "a bit dubious" in terms of API design... but manages to get away with it because it all fits together so neatly.)
Related
I have a class, describing a user in the system:
class userInfo
{
private SomeType1 p1;
private SomeType2 p2;
// ...
private SomeTypek pk;
}
Setting a value to some pi involves a significant amount of code.
Up until now I defined a different method for each pi but the class grew, so I'd like to be able to define a method:
void SetPi(pi, SomeTypei value)
{
//Set pi's value to value
}
Is this kind of thing possible in C#?
Not best idea to design you interaction with DB by that way. But if you want:
public class Class
{
private string p1;
private int p2;
private decimal p3;
public void SetPi<T>(string name, T value)
{
var field = this.GetType().GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (field == null)
throw new ArgumentException("Field not found in Class.");
field.SetValue(this, value);
}
}
Usage:
var c = new Class();
c.SetPi("p1", "AAA");
c.SetPi("p2", 12);
If they were all the same type, I'd suggest that you expose it as a list. Them being different types means that the only way you could do it in one method is to change to a more general type, like object or with generics, T. In doing this, you'll lose type safety and probably complicate the method.
You might want to change your fields into properties, give them descriptive names (assuming you actually have it like this: p1, p2, etc don't make sense, particularly if they're different types; if something like p1, p2 would make sense, that means it should be a list of things, named p or whatever p is short for), and internally call a method to handle the writing (the code is made a bit simpler by using CallerMemberName).
public string UserName
{
get
{
return _userName;
}
set
{
_userName = value;
WriteToDB(value);
}
}
// etc
private void WriteToDB(object value, [CallerMemberName] string propertyName = "")
{
// propertyName will be "UserName" when called above
}
// use like
myUser.UserName = "Tommy";
I don't know whether this will meet your requirements, i.e., is it crucial to use fields and do you have a single value for each type (in both cases the below is definitely not an answer), but here is something which does not involve reflection and is strongly typed:
class UserInfo
{
private static class Cache<T> where T : class
{
public static readonly ConditionalWeakTable<UserInfo, T> ValuesByInstance =
new ConditionalWeakTable<UserInfo, T>();
}
public void SetValue<T>(T value) where T : class
{
Cache<T>.ValuesByInstance.Remove(this);
Cache<T>.ValuesByInstance.Add(this, value);
}
public T GetValue<T>() where T : class
{
T value;
Cache<T>.ValuesByInstance.TryGetValue(this, out value);
return value;
}
}
I have a function with this signature:
public void DoSomething(String name);
The string name is special in my application. It can be either an arbitrary string, or a special known value. Because any non-empty string value is a valid input it means I need to use object reference equality with empty strings, like so:
public class Foo {
public const String SpecialValue1 = "";
public const String SpecialValue2 = "";
public void DoSomething(String name) {
if( Object.ReferenceEquals( name, SpecialValue1 ) ) {
} else if( Object.ReferenceEquals( name, SpecialValue2 ) {
} else {
}
}
public void UsageExample() {
DoSomething( SpecialValue1 );
DoSomething( "some arbitrary value" );
}
}
I want to know if this technique, using empty strings and object reference equality will always be safe, especially with respect to string interning.
Antimony is right about the reasons this will not work.
I would suggest that you define a type for the argument. Let's call it ExampleArgument.
public class ExampleArgument
{
private readonly int _knownValue;
private readonly string _arbitraryValue;
public ExampleArgument(string arbitraryValue)
{
_arbitraryValue = arbitraryValue;
_knownValue = 0;
}
private ExampleArgument(int knownValue)
{
_knownValue = knownValue;
_arbitraryValue = null;
}
public static readonly ExampleArgument FirstKnownValue = new ExampleArgument(1);
public static readonly ExampleArgument SecondKnownValue = new ExampleArgument(2);
// obvious Equals and GetHashCode overloads
// possibly other useful methods that depend on the application
}
Oh, and if you really want the calling syntax in your example, you could add:
public static implicit operator ExampleArgument(string arbitraryValue)
{
return new ExampleArgument(arbitraryValue);
}
Which is an implicit conversion operator from string to ExampleArgument.
DoSomething(ExampleArgument.FirstKnownValue);
DoSomething(new ExampleArgument("hello"));
DoSomething("hello"); // equivalent to previous line, uses implicit conversion operator
No, this is not safe. In fact, this will never work. String literals get interned, so both special values will have the same reference. Most compilers will also intern compile time constant strings, and you can always intern strings manually.
Unfortunately, if you want to accept any valid string, you need some other way to pass extra information. And even if a hack like this worked, it would be a bad idea, since it violates normal string equality semantics.
Here are the possibilities I can think of
If you only have one special value, you can use null
Take a broader type such as Object as input
Take two parameters
Make a separate function
Instead of writing
int i = new int();
i = 7;
One can write
int i = 7;
Is there a way I can get that style of initialisation for my own types?
MyType mt = xyz;
The closest you can come is by creating implicit conversions on your type. For example:
public class Unit
{
public static implicit operator Unit( string val )
{
return Unit.Parse( val );
}
public static Unit Parse( string unitString )
{
// parsing magic goes here
}
}
This would enable you to do something like this:
Unit width = "150px";
var width = Unit.Parse("150px"); // equivalent to previous line
Note that you cannot introduce new syntax; this would be impossible to implement:
Unit width = 150px;
since 150px does not represent a valid value type.
Note that implicit casting can get you into trouble in weird ways so don't over do it. Support implicit casting only to and from types that you're really going to need.
Alternatively, if you're using C# compiler 3.5 or up you can also use inline initialization which is more verbose but also more explicit:
Unit with = new { Value=150, UnitType=Units.Pixel };
For the specific example in your comment you could add an implicit conversion operator to the type.
Note that doing this is generally not recommended because it makes your code less readable. For example, something like String2 s2 = new String2("yo") is completely explicit about what is happening; not so with something like String2 s2 = "yo".
String2 s2 = "yo";
// ...
public sealed class String2
{
public readonly string _value;
public string Value { get { return _value; } }
public String2(string value)
{
_value = value;
}
public override string ToString()
{
return Value;
}
public static implicit operator String2(string value)
{
return new String2(value);
}
}
You can do it through implicit cast operators.
Here's an article that describes the concept:
http://www.codeproject.com/KB/cs/Csharp_implicit_operator.aspx
short answer is "no you can't". You're always going to hide a new somewhere.
In your specific case you could do some trick with implicit conversions like this:
class String2 {
private readonly string WrappedString;
public String2(string wrappedString) {
this.WrappedString = "my modified " + wrappedString ;
}
public override string ToString() {
return this.WrappedString;
}
// the "magic" is here: the string you assign to String2 gets implicitly
// converted to a String2
public static implicit operator String2(string wrappedString) {
return new String2(wrappedString);
}
}
that enables you to do:
String2 test = "test";
Console.WriteLine(test.ToString()); // writes: "my modified test" to the Console
but you get the "new" hidden in the implicit conversion anyway.
Another approach which may be more general and lands you not too far from the syntax you want is through extension methods:
static class StringExtensions {
public static String2 ToString2(this string that) {return new String2(that);}
}
with that in scope, you can do this:
var test2="anothertest".ToString2();
public class Currency{
private Code {get;set;}
public Currency(string code){
this.Code = code;
}
//more methods here
}
I want to be able to make my object castable
string curr = "USD";
Currency myType = (Currency)curr;
I know that I can do it with the contructor, but I have usecase where I need to cast without initializing the object...
I also believe that ill need a function like FromString() to do it
Thanks.
Yes, just add an explicit cast operator:
public class Currency {
private readonly string code;
public string Code { get { return this.code; } }
public Currency(string code) {
this.code = code;
}
//more methods here
public static explicit operator Currency(string code) {
return new Currency(code);
}
}
Now you can say:
string curr = "USD";
Currency myType = (Currency)curr;
Add this method to your Currency class:
public static explicit operator Currency(String input)
{
return new Currency(input);
}
And call it like this:
Currency cur = (Currency)"USD";
If you create your own cast-operators for your type, you can make this possible.
check out the implicit and explicit keywords.
(in this case, I'd prefer an explicit cast).
I believe this operator does what you want (as part of your Currency class):
public static explicit operator Currency(stringvalue){
return new Currency(value);
}
Consider the following code:
public class TextType {
public TextType(String text) {
underlyingString = text;
}
public static implicit operator String(TextType text) {
return text.underlyingString;
}
private String underlyingString;
}
TextType text = new TextType("Something");
String str = text; // This is OK.
But I want to be able do the following, if possible.
TextType textFromStringConstant = "SomeOtherText";
I can't extend the String class with the TextType implicit operator overload, but is there any way to assign a literal string to another class (which is handled by a method or something)?
String is a reference type so when they developed C# they obviously had to use some way to get a string literal to the class. I just hope it's not hardcoded into the language.
public static implicit operator TextType(String text) {
return new TextType(text);
}
Add
public static implicit operator TextType(string content) {
return new TextType(content);
}
to your class? :)