Can an attribute in C# be used with a collection initializer?
For example, I'd like to do something like the following:
[DictionaryAttribute(){{"Key", "Value"}, {"Key", "Value"}}]
public class Foo { ... }
I know attributes can have named parameters, and since that seems pretty similar to object initializers, I was wondering if collection initializers were available as well.
Update: I'm sorry I'm mistaken - pass array of custom type is impossible :(
The types of positional and named parameters for an attribute class
are limited to the attribute parameter types, which are:
One of the following types: bool, byte, char, double, float,
int, long, short, string.
The type object.
The type System.Type.
An Enum type, provided it has public accessibility and the types
in which it is nested (if any) also have public accessibility (Section
17.2).
Single-dimensional arrays of the above types.
source
Source: stackoverflow.
You CAN DECLARE passing an array of a custom type:
class TestType
{
public int Id { get; set; }
public string Value { get; set; }
public TestType(int id, string value)
{
Id = id;
Value = value;
}
}
class TestAttribute : Attribute
{
public TestAttribute(params TestType[] array)
{
//
}
}
but compilation errors occur on the attribute declaration:
[Test(new[]{new TestType(1, "1"), new TestType(2, "2"), })]
public void Test()
{
}
Section 17.1.3 of the C# 4.0 specification specifically does not allow for multidimensional arrays inside the attribute parameters, so while Foo(string[,] bar) might allow you to call Foo(new [,] {{"a", "b"}, {"key2", "val2"}}), it is unfortunately, not available for attributes.
So with that in mind, a few possibilities to approximate what you want are:
Use a single-dimensional array, with alternating key and value pairs. The obvious downside to this approach is that it's not exactly enforcing names and values.
Allow your parameter to appear multiple times by tagging your attribute definition with the following attribute:
[AttributeUsage(AllowMultiple=true)]
In this way, you can now define:
[KeyVal("key1","val1"), KeyVal("key2","val2")]
public class Foo { ... }
This is a bit wordier than what I'm sure you were hoping for, but it makes a clear delineation between names and values.
Find a JSON package and provide an initializer for your attribute. The performance hit is inconsequential as this is done during code initialization. Using Newtonsoft.Json, for instance, you could make an attribute like so:
public class JsonAttribute : Attribute
{
Dictionary<string, string> _nameValues =
new Dictionary<string, string>();
public JsonAttribute(string jsoninit)
{
var dictionary = new Dictionary<string, string>();
dynamic obj = JsonConvert.DeserializeObject(jsoninit);
foreach(var item in obj)
_nameValues[item.Name] = item.Value.Value;
}
}
Which would then allow you to instantiate an attribute like so:
[Json(#"{""key1"":""val1"", ""key2"":""val2""}")]
public class Foo { ... }
I know it's a little quote-happy, a lot more involved, but there you are. Regardless, in this crazy dynamic world, knowing how to initialize objects with JSON isn't a bad skill to have in your back pocket.
The short answer is no.
Longer answer: In order for a class to support collection initializers, it needs to implement IEnumerable and it needs to have an add method. So for example:
public class MyClass<T,U> : IEnumerable<T>
{
public void Add(T t, U u)
{
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I can then do this:
var mc = new MyClass<int, string> {{1, ""}, {2, ""}};
So using this, let's try to make it work for an attribute. (side note, since attributes don't support generics, I'm just hardcoding it using strings for testing) :
public class CollectionInitAttribute : Attribute, IEnumerable<string>
{
public void Add(string s1, string s2)
{
}
public IEnumerator<string> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And now to test it:
[CollectionInit{{"1","1"}}]
public class MyClass
{
}
and that doesn't compile :( I'm not sure where the limitation is exactly, I'm guessing attributes aren't newed up the same way a regular object is and therefore this isn't supported. I'd be curious if this can theoretically be supported by a future version of the language....
Related
I would like to implement the following method:
public static T CreateProxyObject<T>(Dictionary<String,Object> setup)
With the following Rules:
1) I want to stay as generic as possible means T is not known during compile time and I want to be able to return it to user as the mocked/proxy requested type (user can still use normal intellisense to get object's metadata).
2) It should have all its properties set/setup based on the setup Dictionary:
String-> property name of the object
Object-> the return value for this property
Any other method should be implemented with throwing not implemented exception
I was trying to use mock of T (from Moq framework) but T must be reference type.
Had no success as well with Castle DynamicProxy and RealProxy.
Any Idea?
Try castle dictionary adapter
http://kozmic.net/2014/03/22/strongly-typed-app-settings-with-castle-dictionaryadapter/
After searching a bit more I found this answer that guided me to use impromptu-interface which uses expandoobject/dynamic object in order to implement an interface, And together with this answer (which solve the problem of setting the properties dynamically),
I was able to create the following implementation:
public static T CreateProxyObject<T>(Dictionary<String,Object> setup) where T : class
{
return setup.Aggregate(
(IDictionary<string, object>) new ExpandoObject(),
(e, kvSetup) =>
{
e.Add(kvSetup.Key, kvSetup.Value);
return e;
}).ActLike<T>();
}
That can be used like this:
public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
void Method();
}
public class Program
{
static void Main(string[] args)
{
//Dynamic Expando object
var p = CreateProxyObject<IPerson>(new Dictionary<string, object>
{
{"Name", "a name"},
{"Age", 13}
});
var n = p.Name;
var a = p.Age;
//Throws: 'System.Dynamic.ExpandoObject' does not contain a definition for 'Method'
p.Method();
}
}
I am new to C#. I am trying to implement a Dictionary in C# whose Java-equivalent is:
HashMap<string, Variable<?>> dictionary
Here is the detailed Java version of what I'm trying to do: Java how to manage user-defined variables
In C# so far I have something like this:
interface IVariable { }
public class Variable<T> : IVariable
{
public T myValue { get; set; }
}
Dictionary<string, IVariable> vars = new Dictionary<string, IVariable>();
Then I try to do this:
Variable<int> age = new Variable<int>();
age.myValue = 12;
vars.Add("age", age);
IVariable theVar;
if (vars.TryGetValue("age", out theVar) {
Console.WriteLine("fetched age is " + theVar.myValue);
}
I run into trouble in the last line because the compiler doesn't recognize the myValue member of a theVar because it is an IVariable.
In this simple example maybe I could declare theVar to be a Variable<int> instead of an IVariable but I haven't tried it because it would require a priori knowledge about what kind of variable I'm fetching from the dictionary and I might not always have that knowledge.
I wouldn't mind if myValue were an inherited/abstract property (if there is such a thing), since every Variable will have a property named myValue (each will differ in type but not in name). In that case I guess I could make IVariable an abstract class rather than an interface, but then I still run into trouble as far as what to put for the type of myValue.
Could I do a cast of theVar into something using as by first checking its type with is? I'm not sure if that would work or is even possible.
I've looked at these posts for guidance (especially the second one):
Wildcard equivalent in C# generics
C# Generics: wildcards
However, my situation is still slightly different than the second example above because that example has an abstract method that is returning a void whereas I wish to have my variables return non-void generic values.
Thanks for any help.
C# has dynamic. You can create Dictionary<string, dynamic>
Or you can use object (boxing/unboxing) Dictionary<string, object>
Or you can get generic type from class
class MyClass<TDicValue>
{
Dictionary<strint, TDicValue> myDictionary;
}
I had this same problem where I had 20 slightly different types and I had to keep dictionaries on. I wanted to organize them in a list.
The problem was the same, selecting the right kind from the list with reflection or strings lacked the ability to provide a type to return to. #skrilmps answer is correct, but packing and and unpacking was at best unreliable without a lot (metric ton) of ugly messy code.
While unity does support dynamics in 2020, this doesn't exactly work with what i am doing unless I make like everything dynamic safe and that's shamble coding, not extensible or maintainable, and just sounds like a general nightmare.
I personally feel that I am an inadequate programmer after years of trying to learn and still not having my efforts provide a productive return or product of note, so i cannot claim the answer being mine, but in my research on the proper solution to this problem i found this: https://www.youtube.com/watch?v=A7qwuFnyIpM
In here he says basically if you add an interface to your similar classes that are intended for use in a variety of different lists, that you can instead make a list of that type of interface. I would assume dictionary as well, and then you can add any kind of class implementing this interface to this singular interface type defined list.
I tried using boxing/unboxing and came up with this solution. It appears to work... so far. But it doesn't seem very safe.
public interface Variable
{
object getValue();
void setValue(object value);
Type myType();
}
public class Variable<T>: Variable
{
private T myValue;
public object getValue()
{
return myValue;
}
public void setValue(object value)
{
myValue = (T)value;
}
public Type myType() { return myValue.GetType(); }
}
Dictionary<string, Variable> vars = new Dictionary<string, Variable>();
Variable<int> age = new Variable<int>();
age.setValue(21);
vars.Add("age", age);
Variable theAgeVar;
vars.TryGetValue("age", out theAgeVar);
Console.WriteLine("age = " + theAgeVar.getValue());
Variable<double> height = new Variable<double>();
height.setValue(5.9);
Variable theHeightVar;
vars.TryGetValue("age", out theHeightVar);
Debug.Log("height = " + theHeightVar.getValue());
This prints:
age = 21
height = 5.9
One thing I do not like is that I had to make the return type of getValue() be an object. If I wanted myValue (which is of type T) to implement IComparable, for instance, then this information is lost when the boxing happens and the caller receives an object.
// The following should resolve the boxing problem and now is totally generic:
public interface IVariable<T>
{
T GetContent();
void SetContent(T value);
Type GetDataType();
}
public class Variable<T> : IVariable
{
private T content;
public T GetContent()
{
return content;
}
public void SetContent(T value)
{
content = value;
}
public Type GetDataType() { return GetType(); }
}
Dictionary<string, Variable<T>> variables = new Dictionary<string, Variable<T>>();
public class EnumRouteConstraint<T> : IRouteConstraint
where T : struct
{
private static readonly Lazy<HashSet<string>> _enumNames; // <--
static EnumRouteConstraint()
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(
Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
}
string[] names = Enum.GetNames(typeof(T));
_enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
(
names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
));
}
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
bool match = _enumNames.Value.Contains(values[parameterName].ToString());
return match;
}
}
Is this wrong? I would assume that this actually has a static readonly field for each of the possible EnumRouteConstraint<T> that I happen to instance.
It's fine to have a static field in a generic type, so long as you know that you'll really get one field per combination of type arguments. My guess is that R# is just warning you in case you weren't aware of that.
Here's an example of that:
using System;
public class Generic<T>
{
// Of course we wouldn't normally have public fields, but...
public static int Foo;
}
public class Test
{
public static void Main()
{
Generic<string>.Foo = 20;
Generic<object>.Foo = 10;
Console.WriteLine(Generic<string>.Foo); // 20
}
}
As you can see, Generic<string>.Foo is a different field from Generic<object>.Foo - they hold separate values.
From the JetBrains wiki:
In the vast majority of cases, having a static field in a generic type
is a sign of an error. The reason for this is that a static field in a
generic type will not be shared among instances of different close
constructed types. This means that for a generic class C<T> which
has a static field X, the values of C<int>.X and C<string>.X
have completely different, independent values.
In the rare cases when you do need the 'specialized' static fields,
feel free to suppress the warning.
If you need to have a static field shared between instances with
different generic arguments, define a non-generic base class to
store your static members, then set your generic type to inherit from
this type.
This is not necessarily an error - it is warning you about a potential misunderstanding of C# generics.
The easiest way to remember what generics do is the following:
Generics are "blueprints" for creating classes, much like classes are "blueprints" for creating objects. (Well, this is a simplification though. You may use method generics as well.)
From this point of view MyClassRecipe<T> is not a class -- it is a recipe, a blueprint, of what your class would look like. Once you substitute T with something concrete, say int, string, etc., you get a class. It is perfectly legal to have a static member (field, property, method) declared in your newly created class (as in any other class) and no sign of any error here.
It would be somewhat suspicious, at first sight, if you declare static MyStaticProperty<T> Property { get; set; } within your class blueprint, but this is legal too. Your property would be parameterized, or templated, as well.
No wonder in VB statics are called shared. In this case however, you should be aware that such "shared" members are only shared among instances of the same exact class, and not among the distinct classes produced by substituting <T> with something else.
There are several good answers here already, that explain the warning and the reason for it. Several of these state something like having a static field in a generic type generally a mistake.
I thought I'd add an example of how this feature can be useful, i.e. a case where suppressing the R#-warning makes sense.
Imagine you have a set of entity-classes that you want to serialize, say to Xml. You can create a serializer for this using new XmlSerializerFactory().CreateSerializer(typeof(SomeClass)), but then you will have to create a separate serializer for each type. Using generics, you can replace that with the following, which you can place in a generic class that entities can derive from:
new XmlSerializerFactory().CreateSerializer(typeof(T))
Since your probably don't want to generate a new serializer each time you need to serialize an instance of a particular type, you might add this:
public class SerializableEntity<T>
{
// ReSharper disable once StaticMemberInGenericType
private static XmlSerializer _typeSpecificSerializer;
private static XmlSerializer TypeSpecificSerializer
{
get
{
// Only create an instance the first time. In practice,
// that will mean once for each variation of T that is used,
// as each will cause a new class to be created.
if ((_typeSpecificSerializer == null))
{
_typeSpecificSerializer =
new XmlSerializerFactory().CreateSerializer(typeof(T));
}
return _typeSpecificSerializer;
}
}
public virtual string Serialize()
{
// .... prepare for serializing...
// Access _typeSpecificSerializer via the property,
// and call the Serialize method, which depends on
// the specific type T of "this":
TypeSpecificSerializer.Serialize(xmlWriter, this);
}
}
If this class was NOT generic, then each instance of the class would use the same _typeSpecificSerializer.
Since it IS generic however, a set of instances with the same type for T will share a single instance of _typeSpecificSerializer (which will have been created for that specific type), while instances with a different type for T will use different instances of _typeSpecificSerializer.
An example
Provided the two classes that extend SerializableEntity<T>:
// Note that T is MyFirstEntity
public class MyFirstEntity : SerializableEntity<MyFirstEntity>
{
public string SomeValue { get; set; }
}
// Note that T is OtherEntity
public class OtherEntity : SerializableEntity<OtherEntity >
{
public int OtherValue { get; set; }
}
... let's use them:
var firstInst = new MyFirstEntity{ SomeValue = "Foo" };
var secondInst = new MyFirstEntity{ SomeValue = "Bar" };
var thirdInst = new OtherEntity { OtherValue = 123 };
var fourthInst = new OtherEntity { OtherValue = 456 };
var xmlData1 = firstInst.Serialize();
var xmlData2 = secondInst.Serialize();
var xmlData3 = thirdInst.Serialize();
var xmlData4 = fourthInst.Serialize();
In this case, under the hood, firstInst and secondInst will be instances of the same class (namely SerializableEntity<MyFirstEntity>), and as such, they will share an instance of _typeSpecificSerializer.
thirdInst and fourthInst are instances of a different class (SerializableEntity<OtherEntity>), and so will share an instance of _typeSpecificSerializer that is different from the other two.
This means you get different serializer-instances for each of your entity types, while still keeping them static within the context of each actual type (i.e., shared among instances that are of a specific type).
Given the class below:
public class ConcreteEmployeeRoleCreator<T, TConcrete, TSpec>
where TConcrete : class, T, new()
where T : EmployeeRole
where TSpec : EmployeeRoleSpecification
{
public ConcreteEmployeeRoleCreator(TSpec spec) { Specification = spec; }
public TSpec Specification { get; private set; }
public T Create() { return new TConcrete(); }
}
I would like to have a dictionary of 'creators', but I haven't been able to work out how to do it yet. If I try and define the dictionary using the lowest common denominator types, the compiler is not allowing an instance to be added
[Test]
public void Creator_CanCreateFromSpec() {
var creators = new Dictionary<string, ConcreteEmployeeRoleCreator<EmployeeRole, EmployeeRole, EmployeeRoleSpecification>>();
var spec = new SalesmanRoleSpecification();
var creator = new ConcreteEmployeeRoleCreator<EmployeeRole, Salesman, SalesmanRoleSpecification>(spec);
creators.Add("salesman", creator); <==== ** compile error **
}
Salesman is an EmployeeRole, and SalesmanRoleSpecification is an EmployeeRoleSpecification (or I wouldn't be able to define the creator above without a compiler error as well).
SO I guess it is the way I am declaring the dictionary? What am I doing wrong?
Cheers,
Berryl
Generic covariance has to be specified at the declaration of the covariant type - and it can only be specified for interfaces and delegates.
So, given that you're using a class, a
ConcreteEmployeeRoleCreator<EmployeeRole, Salesman, SalesmanRoleSpecification>
will never be a
ConcreteEmployeeRoleCreator<EmployeeRole, EmployeeRole, EmployeeRoleSpecification>
You'll need to look for an alternative approach. To be honest, by the time you get to three type parameters and want two of them to be covariant, you've got a pretty hard-to-understand design to start with, I'm afraid :(
I have an (existing) typed class of items:
Items<T>
T Value { get; }
T can be double, string or int.
I then have a class that has to hold several instances of Items. Within a single instance of this class, T is always the same. As it stands, the type actually contained is determined by a property and the container is not typed:
Data
DataType { get; set; }
Items<double>
double Value;
Items<string>
// ... and so on. Nasty stuff.
Ideally, of course, this would be
Data<T>
Items<T>
T value
Data instances are created from scratch in code, and can be loaded from a database. So of course a factory would be in our future, but what is the return type of the Create method?
Even worse, I need this:
DataCollection
// HERE'S THE PAIN: What's the type here?
List of Data<> instances with differing types
foreach (? data in someDataCollection)
if (thetypeof data is double)
doSomething();
else
doSomethingElse();
Now, I can solve this, but I can't see a CLEAN way to solve this.
My first issue is the declaration of DataCollection. What is the type of the list? List<object>, so it can hold Data<double> and Data<string>?
There actually is a clean way to solve this; you can use a Dictionary with keys of the data type and values which are of type generic Func<> . You then pass the type to your create method, which then looks up the Func<> to use in the Dictionary based on the type, and invokes that Func<> to create or process your object.
Since I am working from pseudo code, basically it would look something like the below; you can play with it and modify it to get it to serve your needs, but this is the basic idea.
First, create a parent class for all data objects; note that this class has a lookup dictionary for functions to invoke on various types, and note that it is abstract:
public abstract class Data
{
// A Lookup dictionary for processing methods
// Note this the functions just return something of type object; specialize as needed
private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary
<Type, Func<object, Data>>()
{
{typeof(int), d => { return doSomethingForInt( (Data<int>) d); }},
{typeof(string), d => { return doSomethingForString( (Data<string>) d); }},
{typeof(double), d => { return doSomethingForDouble( (Data<double>) d); }},
};
// A field indicating the subtype; this will be used for lo
private readonly Type TypeOfThis;
protected Data(Type genericType)
{
TypeOfThis = genericType;
}
public Data Process()
{
return _processFunctions[this.TypeOfThis](this);
}
}
Now subclass Data with a generic type that can be instantiated:
class Data<T> : Data
{
// Set the type on the parent class
public Data() : base(typeof(T))
{
}
// You can convert this to a collection, etc. as needed
public T Items { get; set; }
public static Data<T> CreateData<T>()
{
return new Data<T>();
}
}
You can then create a DataCollection class using the parent type. Note the ProcessData() method; all it does now is loop over the elements and call Process() on each one:
class DataCollection
{
public IList<Data> List = new List<Data>();
public void ProcessData()
{
foreach (var d in List)
{
d.Process();
}
}
}
...and you're all set! Now you can invoke your DataCollection with different types of Data:
DataCollection dc = new DataCollection();
dc.List.Add(new Data<int>());
dc.List.Add(new Data<string>());
dc.List.Add(new Data<double>());
dc.ProcessData();
I think every time you need to do if-conditions on runtime data type, it means there's something wrong with the data structures. But every time I encounter situation like this, I have a hard time to solve it.
What I would try to do here is to wrap your primitive types into some kind of Adapters with conversion methods (possibly even implicit) and make all of them implement a common interface, let's say IDoSomething. Then, you can define the doSomething behaviors in IntWrapper, DoubleWrapper etc. separately. Then your DataCollection should be of type List<IDoSomething> and the loop can just call data.DoSomething() method from the interface.
Having implicit conversion allows you to use the collection in the natural way like data.Add(3) - you'll still be able to add the items without wrapping the privitives